X-Git-Url: http://git.vpit.fr/?a=blobdiff_plain;f=Types.xs;h=6ead2eb61321356b7f6336749e2def7bd224945b;hb=55716e9a7414ca5da96259d66fd0f20c1cbba893;hp=bf6c0bd4ec363d5a027562097985d8ecf23c75d4;hpb=a825e9ba35d8715a17a91575220e61769dd1aa8a;p=perl%2Fmodules%2FLexical-Types.git diff --git a/Types.xs b/Types.xs index bf6c0bd..6ead2eb 100644 --- a/Types.xs +++ b/Types.xs @@ -411,8 +411,6 @@ STATIC SV *lt_hint(pTHX) { #define ptable_map_store(T, K, V) ptable_map_store(aPTBLMS_ (T), (K), (V)) #define ptable_map_delete(T, K) ptable_map_delete(aPTBLMS_ (T), (K)) -STATIC ptable *lt_op_map = NULL; - #ifdef USE_ITHREADS STATIC perl_mutex lt_op_map_mutex; @@ -427,7 +425,10 @@ STATIC perl_mutex lt_op_map_mutex; #endif /* !USE_ITHREADS */ +STATIC ptable *lt_op_padxv_map = NULL; + typedef struct { + OP *(*old_pp)(pTHX); #ifdef MULTIPLICITY STRLEN buf_size, orig_pkg_len, type_pkg_len, type_meth_len; char *buf; @@ -436,18 +437,72 @@ typedef struct { SV *type_pkg; SV *type_meth; #endif /* !MULTIPLICITY */ - OP *(*old_pp)(pTHX); -} lt_op_info; +} lt_op_padxv_info; + +STATIC void lt_op_padxv_info_call(pTHX_ const lt_op_padxv_info *oi, SV *sv) { +#define lt_op_padxv_info_call(O, S) lt_op_padxv_info_call(aTHX_ (O), (S)) + SV *orig_pkg, *type_pkg, *type_meth; + int items; + dSP; + + ENTER; + SAVETMPS; + +#ifdef MULTIPLICITY + { + STRLEN op_len = oi->orig_pkg_len, tp_len = oi->type_pkg_len; + char *buf = oi->buf; + orig_pkg = sv_2mortal(newSVpvn(buf, op_len)); + SvREADONLY_on(orig_pkg); + buf += op_len; + type_pkg = sv_2mortal(newSVpvn(buf, tp_len)); + SvREADONLY_on(type_pkg); + buf += tp_len; + type_meth = sv_2mortal(newSVpvn(buf, oi->type_meth_len)); + SvREADONLY_on(type_meth); + } +#else /* MULTIPLICITY */ + orig_pkg = oi->orig_pkg; + type_pkg = oi->type_pkg; + type_meth = oi->type_meth; +#endif /* !MULTIPLICITY */ -STATIC void lt_map_store(pTHX_ const OP *o, SV *orig_pkg, SV *type_pkg, SV *type_meth, OP *(*old_pp)(pTHX)) { -#define lt_map_store(O, OP, TP, TM, PP) lt_map_store(aTHX_ (O), (OP), (TP), (TM), (PP)) - lt_op_info *oi; + PUSHMARK(SP); + EXTEND(SP, 3); + PUSHs(type_pkg); + PUSHs(sv); + PUSHs(orig_pkg); + PUTBACK; + + items = call_sv(type_meth, G_ARRAY | G_METHOD); + + SPAGAIN; + switch (items) { + case 0: + break; + case 1: + sv_setsv(sv, POPs); + break; + default: + croak("Typed scalar initializer method should return zero or one scalar, but got %d", items); + } + PUTBACK; + + FREETMPS; + LEAVE; + + return; +} + +STATIC void lt_padxv_map_store(pTHX_ const OP *o, SV *orig_pkg, SV *type_pkg, SV *type_meth, OP *(*old_pp)(pTHX)) { +#define lt_padxv_map_store(O, OP, TP, TM, PP) lt_padxv_map_store(aTHX_ (O), (OP), (TP), (TM), (PP)) + lt_op_padxv_info *oi; LT_LOCK(<_op_map_mutex); - if (!(oi = ptable_fetch(lt_op_map, o))) { + if (!(oi = ptable_fetch(lt_op_padxv_map, o))) { oi = PerlMemShared_malloc(sizeof *oi); - ptable_map_store(lt_op_map, o, oi); + ptable_map_store(lt_op_padxv_map, o, oi); #ifdef MULTIPLICITY oi->buf = NULL; oi->buf_size = 0; @@ -495,12 +550,54 @@ STATIC void lt_map_store(pTHX_ const OP *o, SV *orig_pkg, SV *type_pkg, SV *type LT_UNLOCK(<_op_map_mutex); } -STATIC const lt_op_info *lt_map_fetch(const OP *o, lt_op_info *oi) { - const lt_op_info *val; +STATIC const lt_op_padxv_info *lt_padxv_map_fetch(const OP *o, lt_op_padxv_info *oi) { + const lt_op_padxv_info *val; + + LT_LOCK(<_op_map_mutex); + + val = ptable_fetch(lt_op_padxv_map, o); + if (val) { + *oi = *val; + val = oi; + } + + LT_UNLOCK(<_op_map_mutex); + + return val; +} + +#if LT_HAS_PERL(5, 17, 6) + +STATIC ptable *lt_op_padrange_map = NULL; + +typedef struct { + OP *(*old_pp)(pTHX); + const OP *padxv_start; +} lt_op_padrange_info; + +STATIC void lt_padrange_map_store(pTHX_ const OP *o, const OP *s, OP *(*old_pp)(pTHX)) { +#define lt_padrange_map_store(O, S, PP) lt_padrange_map_store(aTHX_ (O), (S), (PP)) + lt_op_padrange_info *oi; + + LT_LOCK(<_op_map_mutex); + + if (!(oi = ptable_fetch(lt_op_padrange_map, o))) { + oi = PerlMemShared_malloc(sizeof *oi); + ptable_map_store(lt_op_padrange_map, o, oi); + } + + oi->old_pp = old_pp; + oi->padxv_start = s; + + LT_UNLOCK(<_op_map_mutex); +} + +STATIC const lt_op_padrange_info *lt_padrange_map_fetch(const OP *o, lt_op_padrange_info *oi) { + const lt_op_padrange_info *val; LT_LOCK(<_op_map_mutex); - val = ptable_fetch(lt_op_map, o); + val = ptable_fetch(lt_op_padrange_map, o); if (val) { *oi = *val; val = oi; @@ -511,11 +608,16 @@ STATIC const lt_op_info *lt_map_fetch(const OP *o, lt_op_info *oi) { return val; } +#endif + STATIC void lt_map_delete(pTHX_ const OP *o) { #define lt_map_delete(O) lt_map_delete(aTHX_ (O)) LT_LOCK(<_op_map_mutex); - ptable_map_delete(lt_op_map, o); + ptable_map_delete(lt_op_padxv_map, o); +#if LT_HAS_PERL(5, 17, 6) + ptable_map_delete(lt_op_padrange_map, o); +#endif LT_UNLOCK(<_op_map_mutex); } @@ -525,66 +627,45 @@ STATIC void lt_map_delete(pTHX_ const OP *o) { /* ... Our pp_padsv ........................................................ */ STATIC OP *lt_pp_padsv(pTHX) { - lt_op_info oi; + lt_op_padxv_info oi; - if (lt_map_fetch(PL_op, &oi)) { - SV *orig_pkg, *type_pkg, *type_meth; - int items; - dSP; + if (lt_padxv_map_fetch(PL_op, &oi)) { dTARGET; + lt_op_padxv_info_call(&oi, TARG); + return oi.old_pp(aTHX); + } - ENTER; - SAVETMPS; + return PL_op->op_ppaddr(aTHX); +} -#ifdef MULTIPLICITY - { - STRLEN op_len = oi.orig_pkg_len, tp_len = oi.type_pkg_len; - char *buf = oi.buf; - orig_pkg = sv_2mortal(newSVpvn(buf, op_len)); - SvREADONLY_on(orig_pkg); - buf += op_len; - type_pkg = sv_2mortal(newSVpvn(buf, tp_len)); - SvREADONLY_on(type_pkg); - buf += tp_len; - type_meth = sv_2mortal(newSVpvn(buf, oi.type_meth_len)); - SvREADONLY_on(type_meth); - } -#else /* MULTIPLICITY */ - orig_pkg = oi.orig_pkg; - type_pkg = oi.type_pkg; - type_meth = oi.type_meth; -#endif /* !MULTIPLICITY */ +/* ... Our pp_padrange (on perl 5.17.6 and above) .......................... */ - PUSHMARK(SP); - EXTEND(SP, 3); - PUSHs(type_pkg); - PUSHTARG; - PUSHs(orig_pkg); - PUTBACK; +#if LT_HAS_PERL(5, 17, 6) - items = call_sv(type_meth, G_ARRAY | G_METHOD); +STATIC OP *lt_pp_padrange(pTHX) { + lt_op_padrange_info roi; - SPAGAIN; - switch (items) { - case 0: - break; - case 1: - sv_setsv(TARG, POPs); - break; - default: - croak("Typed scalar initializer method should return zero or one scalar, but got %d", items); - } - PUTBACK; + if (lt_padrange_map_fetch(PL_op, &roi)) { + PADOFFSET i, base, count; + const OP *p; - FREETMPS; - LEAVE; + base = PL_op->op_targ; + count = PL_op->op_private & OPpPADRANGE_COUNTMASK; - return oi.old_pp(aTHX); + for (i = 0, p = roi.padxv_start; i < count && p; ++i, p = p->op_sibling) { + lt_op_padxv_info oi; + if (p->op_type == OP_PADSV && lt_padxv_map_fetch(p, &oi)) + lt_op_padxv_info_call(&oi, PAD_SV(base + i)); + } + + return roi.old_pp(aTHX); } return PL_op->op_ppaddr(aTHX); } +#endif + /* ... Our ck_pad{any,sv} .................................................. */ /* Sadly, the padsv OPs we are interested in don't trigger the padsv check @@ -662,7 +743,7 @@ STATIC OP *lt_ck_padany(pTHX_ OP *o) { SvREFCNT_inc_simple_void_NN(orig_meth); } - lt_map_store(o, orig_pkg, type_pkg, type_meth, o->op_ppaddr); + lt_padxv_map_store(o, orig_pkg, type_pkg, type_meth, o->op_ppaddr); } else { skip: lt_map_delete(o); @@ -681,13 +762,42 @@ STATIC OP *lt_ck_padsv(pTHX_ OP *o) { /* ... Our peephole optimizer .............................................. */ +#if LT_HAS_PERL(5, 17, 6) + +STATIC int lt_maybe_padrange_setup(pTHX_ OP *o, const OP *start) { +#define lt_maybe_padrange_setup(O, S) lt_maybe_padrange_setup(aTHX_ (O), (S)) + PADOFFSET i, count; + const OP *p; + + count = o->op_private & OPpPADRANGE_COUNTMASK; + + for (i = 0, p = start; i < count && p; ++i, p = p->op_sibling) { + if (p->op_type == OP_PADSV) { + /* In a padrange sequence, either all lexicals are typed, or none are. + * Thus we can stop at the first padsv op. However, note that these + * lexicals can need to call different methods in different packages. */ + LT_LOCK(<_op_map_mutex); + if (ptable_fetch(lt_op_padxv_map, p)) { + LT_UNLOCK(<_op_map_mutex); + lt_padrange_map_store(o, start, o->op_ppaddr); + o->op_ppaddr = lt_pp_padrange; + } else { + LT_UNLOCK(<_op_map_mutex); + } + return 1; + } + } + + return 0; +} + +#endif + STATIC peep_t lt_old_peep = 0; /* This is actually the rpeep past 5.13.5 */ STATIC void lt_peep_rec(pTHX_ OP *o, ptable *seen) { #define lt_peep_rec(O) lt_peep_rec(aTHX_ (O), seen) for (; o; o = o->op_next) { - lt_op_info *oi = NULL; - if (ptable_fetch(seen, o)) break; ptable_seen_store(seen, o, o); @@ -695,8 +805,9 @@ STATIC void lt_peep_rec(pTHX_ OP *o, ptable *seen) { switch (o->op_type) { case OP_PADSV: if (o->op_ppaddr != lt_pp_padsv && o->op_private & OPpLVAL_INTRO) { + lt_op_padxv_info *oi; LT_LOCK(<_op_map_mutex); - oi = ptable_fetch(lt_op_map, o); + oi = ptable_fetch(lt_op_padxv_map, o); if (oi) { oi->old_pp = o->op_ppaddr; o->op_ppaddr = lt_pp_padsv; @@ -704,6 +815,34 @@ STATIC void lt_peep_rec(pTHX_ OP *o, ptable *seen) { LT_UNLOCK(<_op_map_mutex); } break; +#if LT_HAS_PERL(5, 17, 6) + case OP_PADRANGE: + /* We deal with special padrange ops later, in the aassign op they belong + * to. */ + if (o->op_ppaddr != lt_pp_padrange && o->op_private & OPpLVAL_INTRO + && !(o->op_flags & OPf_SPECIAL)) { + /* A padrange op is guaranteed to have previously been a pushmark. + * Moreover, for non-special padrange ops (i.e. that aren't for + * my (...) = @_), the original padxv ops are its siblings. */ + lt_maybe_padrange_setup(o, o->op_sibling); + } + break; + case OP_AASSIGN: { + OP *op; + if (cBINOPo->op_first && cBINOPo->op_first->op_flags & OPf_KIDS + && (op = cUNOPx(cBINOPo->op_first)->op_first) + && op->op_type == OP_PADRANGE + && op->op_ppaddr != lt_pp_padrange + && op->op_private & OPpLVAL_INTRO + && op->op_flags & OPf_SPECIAL) { + const OP *start = cUNOPx(cBINOPo->op_last)->op_first; + if (start->op_type == OP_PUSHMARK) + start = start->op_sibling; + lt_maybe_padrange_setup(op, start); + } + break; + } +#endif #if !LT_HAS_RPEEP case OP_MAPWHILE: case OP_GREPWHILE: @@ -840,7 +979,10 @@ BOOT: if (!lt_booted++) { HV *stash; - lt_op_map = ptable_new(); + lt_op_padxv_map = ptable_new(); +#if LT_HAS_PERL(5, 17, 6) + lt_op_padrange_map = ptable_new(); +#endif #ifdef USE_ITHREADS MUTEX_INIT(<_op_map_mutex); #endif