diff options
Diffstat (limited to 'ext/arybase/arybase.xs')
-rw-r--r-- | ext/arybase/arybase.xs | 496 |
1 files changed, 0 insertions, 496 deletions
diff --git a/ext/arybase/arybase.xs b/ext/arybase/arybase.xs deleted file mode 100644 index 6c12d0515f..0000000000 --- a/ext/arybase/arybase.xs +++ /dev/null @@ -1,496 +0,0 @@ -#define PERL_NO_GET_CONTEXT /* we want efficiency */ -#define PERL_EXT -#include "EXTERN.h" -#include "perl.h" -#include "XSUB.h" -#include "feature.h" - -/* ... op => info map ................................................. */ - -typedef struct { - OP *(*old_pp)(pTHX); - IV base; -} ab_op_info; - -#define PTABLE_NAME ptable_map -#define PTABLE_VAL_FREE(V) PerlMemShared_free(V) -#include "ptable.h" -#define ptable_map_store(T, K, V) ptable_map_store(aPTBLMS_ (T), (K), (V)) - -STATIC ptable *ab_op_map = NULL; - -#ifdef USE_ITHREADS -STATIC perl_mutex ab_op_map_mutex; -#endif - -STATIC const ab_op_info *ab_map_fetch(const OP *o, ab_op_info *oi) { - const ab_op_info *val; - - MUTEX_LOCK(&ab_op_map_mutex); - - val = (ab_op_info *)ptable_fetch(ab_op_map, o); - if (val) { - *oi = *val; - val = oi; - } - - MUTEX_UNLOCK(&ab_op_map_mutex); - - return val; -} - -STATIC const ab_op_info *ab_map_store_locked( - pPTBLMS_ const OP *o, OP *(*old_pp)(pTHX), IV base -) { -#define ab_map_store_locked(O, PP, B) \ - ab_map_store_locked(aPTBLMS_ (O), (PP), (B)) - ab_op_info *oi; - - if (!(oi = (ab_op_info *)ptable_fetch(ab_op_map, o))) { - oi = (ab_op_info *)PerlMemShared_malloc(sizeof *oi); - ptable_map_store(ab_op_map, o, oi); - } - - oi->old_pp = old_pp; - oi->base = base; - return oi; -} - -STATIC void ab_map_store( - pPTBLMS_ const OP *o, OP *(*old_pp)(pTHX), IV base) -{ -#define ab_map_store(O, PP, B) ab_map_store(aPTBLMS_ (O),(PP),(B)) - - MUTEX_LOCK(&ab_op_map_mutex); - - ab_map_store_locked(o, old_pp, base); - - MUTEX_UNLOCK(&ab_op_map_mutex); -} - -STATIC void ab_map_delete(pTHX_ const OP *o) { -#define ab_map_delete(O) ab_map_delete(aTHX_ (O)) - MUTEX_LOCK(&ab_op_map_mutex); - - ptable_map_store(ab_op_map, o, NULL); - - MUTEX_UNLOCK(&ab_op_map_mutex); -} - -/* ... $[ Implementation .............................................. */ - -#define hintkey "$[" -#define hintkey_len (sizeof(hintkey)-1) - -STATIC SV * ab_hint(pTHX_ const bool create) { -#define ab_hint(c) ab_hint(aTHX_ c) - dVAR; - SV **val - = hv_fetch(GvHV(PL_hintgv), hintkey, hintkey_len, create); - if (!val) - return 0; - return *val; -} - -/* current base at compile time */ -STATIC IV current_base(pTHX) { -#define current_base() current_base(aTHX) - SV *hsv = ab_hint(0); - assert(FEATURE_ARYBASE_IS_ENABLED); - if (!hsv || !SvOK(hsv)) return 0; - return SvIV(hsv); -} - -STATIC void set_arybase_to(pTHX_ IV base) { -#define set_arybase_to(base) set_arybase_to(aTHX_ (base)) - dVAR; - SV *hsv = ab_hint(1); - sv_setiv_mg(hsv, base); -} - -#define old_ck(opname) STATIC OP *(*ab_old_ck_##opname)(pTHX_ OP *) = 0 -old_ck(sassign); -old_ck(aassign); -old_ck(aelem); -old_ck(aslice); -old_ck(lslice); -old_ck(av2arylen); -old_ck(splice); -old_ck(keys); -old_ck(each); -old_ck(substr); -old_ck(rindex); -old_ck(index); -old_ck(pos); - -STATIC bool ab_op_is_dollar_bracket(pTHX_ OP *o) { -#define ab_op_is_dollar_bracket(o) ab_op_is_dollar_bracket(aTHX_ (o)) - OP *c; - return o->op_type == OP_RV2SV && (o->op_flags & OPf_KIDS) - && (c = cUNOPx(o)->op_first) - && c->op_type == OP_GV - && GvSTASH(cGVOPx_gv(c)) == PL_defstash - && strEQ(GvNAME(cGVOPx_gv(c)), "["); -} - -STATIC void ab_neuter_dollar_bracket(pTHX_ OP *o) { -#define ab_neuter_dollar_bracket(o) ab_neuter_dollar_bracket(aTHX_ (o)) - OP *oldc, *newc; - /* - * Must replace the core's $[ with something that can accept assignment - * of non-zero value and can be local()ised. Simplest thing is a - * different global variable. - */ - oldc = cUNOPx(o)->op_first; - newc = newGVOP(OP_GV, 0, - gv_fetchpvs("arybase::leftbrack", GV_ADDMULTI, SVt_PVGV)); - /* replace oldc with newc */ - op_sibling_splice(o, NULL, 1, newc); - op_free(oldc); -} - -STATIC void ab_process_assignment(pTHX_ OP *left, OP *right) { -#define ab_process_assignment(l, r) \ - ab_process_assignment(aTHX_ (l), (r)) - if (ab_op_is_dollar_bracket(left) && right->op_type == OP_CONST) { - IV base = SvIV(cSVOPx_sv(right)); - set_arybase_to(base); - ab_neuter_dollar_bracket(left); - if (base) { - Perl_ck_warner_d(aTHX_ - packWARN(WARN_DEPRECATED), "Use of assignment to $[ is deprecated" - ", and will be fatal in Perl 5.30" - ); - } - } -} - -STATIC OP *ab_ck_sassign(pTHX_ OP *o) { - o = (*ab_old_ck_sassign)(aTHX_ o); - if (o->op_type == OP_SASSIGN && FEATURE_ARYBASE_IS_ENABLED) { - OP *right = cBINOPx(o)->op_first; - OP *left = OpSIBLING(right); - if (left) ab_process_assignment(left, right); - } - return o; -} - -STATIC OP *ab_ck_aassign(pTHX_ OP *o) { - o = (*ab_old_ck_aassign)(aTHX_ o); - if (o->op_type == OP_AASSIGN && FEATURE_ARYBASE_IS_ENABLED) { - OP *right = cBINOPx(o)->op_first; - OP *left = OpSIBLING(right); - left = OpSIBLING(cBINOPx(left)->op_first); - right = OpSIBLING(cBINOPx(right)->op_first); - ab_process_assignment(left, right); - } - return o; -} - -STATIC void -tie(pTHX_ SV * const sv, SV * const obj, HV *const stash) -{ - SV *rv = newSV_type(SVt_RV); - - SvRV_set(rv, obj ? SvREFCNT_inc_simple_NN(obj) : newSV(0)); - SvROK_on(rv); - sv_bless(rv, stash); - - sv_unmagic((SV *)sv, PERL_MAGIC_tiedscalar); - sv_magic((SV *)sv, rv, PERL_MAGIC_tiedscalar, NULL, 0); - SvREFCNT_dec(rv); /* As sv_magic increased it by one. */ -} - -/* This function converts from base-based to 0-based an index to be passed - as an argument. */ -static IV -adjust_index(IV index, IV base) -{ - if (index >= base || index > -1) return index-base; - return index; -} -/* This function converts from 0-based to base-based an index to - be returned. */ -static IV -adjust_index_r(IV index, IV base) -{ - return index + base; -} - -#define replace_sv(sv,base) \ - ((sv) = sv_2mortal(newSViv(adjust_index(SvIV(sv),base)))) -#define replace_sv_r(sv,base) \ - ((sv) = sv_2mortal(newSViv(adjust_index_r(SvIV(sv),base)))) - -static OP *ab_pp_basearg(pTHX) { - dVAR; dSP; - SV **firstp = NULL; - SV **svp; - UV count = 1; - ab_op_info oi; - Zero(&oi, 1, ab_op_info); - ab_map_fetch(PL_op, &oi); - - switch (PL_op->op_type) { - case OP_AELEM: - firstp = SP; - break; - case OP_ASLICE: - firstp = PL_stack_base + TOPMARK + 1; - count = SP-firstp; - break; - case OP_LSLICE: - firstp = PL_stack_base + *(PL_markstack_ptr-1)+1; - count = TOPMARK - *(PL_markstack_ptr-1); - if (GIMME_V != G_ARRAY) { - firstp += count-1; - count = 1; - } - break; - case OP_SPLICE: - if (SP - PL_stack_base - TOPMARK >= 2) - firstp = PL_stack_base + TOPMARK + 2; - else count = 0; - break; - case OP_SUBSTR: - firstp = SP-(PL_op->op_private & 7)+2; - break; - default: - DIE(aTHX_ - "panic: invalid op type for arybase.xs:ab_pp_basearg: %d", - PL_op->op_type); - } - svp = firstp; - while (count--) replace_sv(*svp,oi.base), svp++; - return (*oi.old_pp)(aTHX); -} - -static OP *ab_pp_av2arylen(pTHX) { - dSP; dVAR; - SV *sv; - ab_op_info oi; - OP *ret; - Zero(&oi, 1, ab_op_info); - ab_map_fetch(PL_op, &oi); - ret = (*oi.old_pp)(aTHX); - if (PL_op->op_flags & OPf_MOD || LVRET) { - sv = newSV(0); - tie(aTHX_ sv, TOPs, gv_stashpv("arybase::mg",1)); - SETs(sv); - } - else { - SvGETMAGIC(TOPs); - if (SvOK(TOPs)) replace_sv_r(TOPs, oi.base); - } - return ret; -} - -static OP *ab_pp_keys(pTHX) { - dVAR; dSP; - ab_op_info oi; - OP *retval; - const I32 offset = SP - PL_stack_base; - SV **svp; - Zero(&oi, 1, ab_op_info); - ab_map_fetch(PL_op, &oi); - retval = (*oi.old_pp)(aTHX); - if (GIMME_V == G_SCALAR) return retval; - SPAGAIN; - svp = PL_stack_base + offset; - while (svp <= SP) replace_sv_r(*svp,oi.base), ++svp; - return retval; -} - -static OP *ab_pp_each(pTHX) { - dVAR; dSP; - ab_op_info oi; - OP *retval; - const I32 offset = SP - PL_stack_base; - Zero(&oi, 1, ab_op_info); - ab_map_fetch(PL_op, &oi); - retval = (*oi.old_pp)(aTHX); - SPAGAIN; - if (GIMME_V == G_SCALAR) { - if (SvOK(TOPs)) replace_sv_r(TOPs,oi.base); - } - else if (offset < SP - PL_stack_base) replace_sv_r(TOPm1s,oi.base); - return retval; -} - -static OP *ab_pp_index(pTHX) { - dVAR; dSP; - ab_op_info oi; - OP *retval; - Zero(&oi, 1, ab_op_info); - ab_map_fetch(PL_op, &oi); - if (MAXARG == 3 && TOPs) replace_sv(TOPs,oi.base); - retval = (*oi.old_pp)(aTHX); - SPAGAIN; - replace_sv_r(TOPs,oi.base); - return retval; -} - -static OP *ab_ck_base(pTHX_ OP *o) -{ - OP * (*old_ck)(pTHX_ OP *o) = 0; - OP * (*new_pp)(pTHX) = ab_pp_basearg; - switch (o->op_type) { - case OP_AELEM : old_ck = ab_old_ck_aelem ; break; - case OP_ASLICE : old_ck = ab_old_ck_aslice ; break; - case OP_LSLICE : old_ck = ab_old_ck_lslice ; break; - case OP_AV2ARYLEN: old_ck = ab_old_ck_av2arylen; break; - case OP_SPLICE : old_ck = ab_old_ck_splice ; break; - case OP_KEYS : old_ck = ab_old_ck_keys ; break; - case OP_EACH : old_ck = ab_old_ck_each ; break; - case OP_SUBSTR : old_ck = ab_old_ck_substr ; break; - case OP_RINDEX : old_ck = ab_old_ck_rindex ; break; - case OP_INDEX : old_ck = ab_old_ck_index ; break; - case OP_POS : old_ck = ab_old_ck_pos ; break; - default: - DIE(aTHX_ - "panic: invalid op type for arybase.xs:ab_ck_base: %d", - PL_op->op_type); - } - o = (*old_ck)(aTHX_ o); - if (!FEATURE_ARYBASE_IS_ENABLED) return o; - /* We need two switch blocks, as the type may have changed. */ - switch (o->op_type) { - case OP_AELEM : - case OP_ASLICE : - case OP_LSLICE : - case OP_SPLICE : - case OP_SUBSTR : break; - case OP_POS : - case OP_AV2ARYLEN: new_pp = ab_pp_av2arylen ; break; - case OP_AKEYS : new_pp = ab_pp_keys ; break; - case OP_AEACH : new_pp = ab_pp_each ; break; - case OP_RINDEX : - case OP_INDEX : new_pp = ab_pp_index ; break; - default: return o; - } - { - IV const base = current_base(); - if (base) { - ab_map_store(o, o->op_ppaddr, base); - o->op_ppaddr = new_pp; - /* Break the aelemfast optimisation */ - if (o->op_type == OP_AELEM) { - OP *const first = cBINOPo->op_first; - OP *second = OpSIBLING(first); - OP *newop; - if (second->op_type == OP_CONST) { - /* cut out second arg and replace it with a new unop which is - * the parent of that arg */ - op_sibling_splice(o, first, 1, NULL); - newop = newUNOP(OP_NULL,0,second); - op_sibling_splice(o, first, 0, newop); - } - } - } - else ab_map_delete(o); - } - return o; -} - - -STATIC U32 ab_initialized = 0; - -/* --- XS ------------------------------------------------------------- */ - -MODULE = arybase PACKAGE = arybase -PROTOTYPES: DISABLE - -BOOT: -{ - if (!ab_initialized++) { - ab_op_map = ptable_new(); - MUTEX_INIT(&ab_op_map_mutex); -#define check(uc,lc,ck) \ - wrap_op_checker(OP_##uc, ab_ck_##ck, &ab_old_ck_##lc) - check(SASSIGN, sassign, sassign); - check(AASSIGN, aassign, aassign); - check(AELEM, aelem, base); - check(ASLICE, aslice, base); - check(LSLICE, lslice, base); - check(AV2ARYLEN,av2arylen,base); - check(SPLICE, splice, base); - check(KEYS, keys, base); - check(EACH, each, base); - check(SUBSTR, substr, base); - check(RINDEX, rindex, base); - check(INDEX, index, base); - check(POS, pos, base); - } -} - -void -_tie_it(SV *sv) - INIT: - GV * const gv = (GV *)sv; - CODE: - if (GvSV(gv)) - /* This is *our* scalar now! */ - sv_unmagic(GvSV(gv), PERL_MAGIC_sv); - tie(aTHX_ GvSVn(gv), NULL, GvSTASH(CvGV(cv))); - -void -FETCH(...) - PREINIT: - SV *ret = FEATURE_ARYBASE_IS_ENABLED - ? cop_hints_fetch_pvs(PL_curcop, "$[", 0) - : 0; - PPCODE: - if (!ret || !SvOK(ret)) mXPUSHi(0); - else XPUSHs(ret); - -void -STORE(SV *sv, IV newbase) - CODE: - PERL_UNUSED_VAR(sv); - if (FEATURE_ARYBASE_IS_ENABLED) { - SV *base = cop_hints_fetch_pvs(PL_curcop, "$[", 0); - if (SvOK(base) ? SvIV(base) == newbase : !newbase) XSRETURN_EMPTY; - Perl_croak(aTHX_ "That use of $[ is unsupported"); - } - else if (newbase) - Perl_croak(aTHX_ "Assigning non-zero to $[ is no longer possible"); - - -MODULE = arybase PACKAGE = arybase::mg -PROTOTYPES: DISABLE - -void -FETCH(SV *sv) - PPCODE: - if (!SvROK(sv) || SvTYPE(SvRV(sv)) >= SVt_PVAV) - Perl_croak(aTHX_ "Not a SCALAR reference"); - { - SV *base = FEATURE_ARYBASE_IS_ENABLED - ? cop_hints_fetch_pvs(PL_curcop, "$[", 0) - : 0; - SvGETMAGIC(SvRV(sv)); - if (!SvOK(SvRV(sv))) XSRETURN_UNDEF; - mXPUSHi(adjust_index_r( - SvIV_nomg(SvRV(sv)), base&&SvOK(base)?SvIV(base):0 - )); - } - -void -STORE(SV *sv, SV *newbase) - CODE: - if (!SvROK(sv) || SvTYPE(SvRV(sv)) >= SVt_PVAV) - Perl_croak(aTHX_ "Not a SCALAR reference"); - { - SV *base = FEATURE_ARYBASE_IS_ENABLED - ? cop_hints_fetch_pvs(PL_curcop, "$[", 0) - : 0; - SvGETMAGIC(newbase); - if (!SvOK(newbase)) SvSetMagicSV(SvRV(sv),&PL_sv_undef); - else - sv_setiv_mg( - SvRV(sv), - adjust_index( - SvIV_nomg(newbase), base&&SvOK(base)?SvIV(base):0 - ) - ); - } |