X-Git-Url: http://git.vpit.fr/?a=blobdiff_plain;f=Types.xs;h=a6df2b9f8f2e08e40cd09ef04e5e508033c9efb0;hb=311cc872692b73075296805143f6a2d8c4074254;hp=2e8bda47037bcbf9f595dc9f0ae72325831138ea;hpb=09c7a37f3be8034a8c04c2011208724e04441d83;p=perl%2Fmodules%2FLexical-Types.git diff --git a/Types.xs b/Types.xs index 2e8bda4..a6df2b9 100644 --- a/Types.xs +++ b/Types.xs @@ -6,6 +6,9 @@ #include "perl.h" #include "XSUB.h" +#define __PACKAGE__ "Lexical::Types" +#define __PACKAGE_LEN__ (sizeof(__PACKAGE__)-1) + /* --- Compatibility wrappers ---------------------------------------------- */ #define LT_HAS_PERL(R, V, S) (PERL_REVISION > (R) || (PERL_REVISION == (R) && (PERL_VERSION > (V) || (PERL_VERSION == (V) && (PERL_SUBVERSION >= (S)))))) @@ -32,9 +35,6 @@ # define HvNAMELEN_get(H) strlen(HvNAME_get(H)) #endif -#define __PACKAGE__ "Lexical::Types" -#define __PACKAGE_LEN__ (sizeof(__PACKAGE__)-1) - /* --- Helpers ------------------------------------------------------------- */ /* ... Hints ............................................................... */ @@ -61,10 +61,11 @@ STATIC SV *lt_hint(pTHX) { /* ... op => info map ...................................................... */ -#define OP2STR_BUF char buf[(CHAR_BIT * sizeof(UV)) / 2] -#define OP2STR(O) (sprintf(buf, "%"UVxf, PTR2UV(O))) +#define PTABLE_VAL_FREE(V) PerlMemShared_free(V) + +#include "ptable.h" -STATIC HV *lt_op_map = NULL; +STATIC ptable *lt_op_map = NULL; typedef struct { SV *orig_pkg; @@ -73,38 +74,32 @@ typedef struct { OP *(*pp_padsv)(pTHX); } lt_op_info; -STATIC void lt_map_store(pTHX_ const OP *o, SV *orig_pkg, SV *type_pkg, SV *type_meth, OP *(*pp_padsv)(pTHX)) { -#define lt_map_store(O, P1, P2, M, PP) lt_map_store(aTHX_ (O), (P1), (P2), (M), (PP)) - OP2STR_BUF; - SV *val; - lt_op_info *oi; +STATIC void lt_map_store(const OP *o, SV *orig_pkg, SV *type_pkg, SV *type_meth, OP *(*pp_padsv)(pTHX)) { + lt_op_info *oi = ptable_fetch(lt_op_map, o); + + if (!oi) { + oi = PerlMemShared_malloc(sizeof *oi); + ptable_store(lt_op_map, o, oi); + } - Newx(oi, 1, lt_op_info); oi->orig_pkg = orig_pkg; oi->type_pkg = type_pkg; oi->type_meth = type_meth; oi->pp_padsv = pp_padsv; - val = newSVuv(PTR2UV(oi)); - - (void)hv_store(lt_op_map, buf, OP2STR(o), val, 0); } -STATIC const lt_op_info *lt_map_fetch(pTHX_ const OP *o) { -#define lt_map_fetch(O) lt_map_fetch(aTHX_ (O)) - OP2STR_BUF; - SV **svp; +STATIC const lt_op_info *lt_map_fetch(const OP *o) { + const lt_op_info *oi; - svp = hv_fetch(lt_op_map, buf, OP2STR(o), 0); + oi = ptable_fetch(lt_op_map, o); - return svp ? INT2PTR(const lt_op_info *, SvUVX(*svp)) : NULL; + return oi; } /* --- Hooks --------------------------------------------------------------- */ /* ... Our pp_padsv ........................................................ */ -STATIC OP *(*lt_old_pp_padsv)(pTHX) = 0; - STATIC OP *lt_pp_padsv(pTHX) { const lt_op_info *oi; @@ -147,7 +142,28 @@ STATIC OP *lt_pp_padsv(pTHX) { return CALL_FPTR(oi->pp_padsv)(aTHX); } - return CALL_FPTR(lt_old_pp_padsv)(aTHX); + return CALL_FPTR(PL_ppaddr[OP_PADSV])(aTHX); +} + +STATIC OP *(*lt_pp_padsv_saved)(pTHX) = 0; + +STATIC void lt_pp_padsv_save(void) { + if (lt_pp_padsv_saved) + return; + + lt_pp_padsv_saved = PL_ppaddr[OP_PADSV]; + PL_ppaddr[OP_PADSV] = lt_pp_padsv; +} + +STATIC void lt_pp_padsv_restore(OP *o) { + if (!lt_pp_padsv_saved) + return; + + if (o->op_ppaddr == lt_pp_padsv) + o->op_ppaddr = lt_pp_padsv_saved; + + PL_ppaddr[OP_PADSV] = lt_pp_padsv_saved; + lt_pp_padsv_saved = 0; } /* ... Our ck_pad{any,sv} .................................................. */ @@ -168,7 +184,7 @@ STATIC OP *lt_ck_padany(pTHX_ OP *o) { HV *stash; SV *hint; - PL_ppaddr[OP_PADSV] = lt_old_pp_padsv; + lt_pp_padsv_restore(o); o = CALL_FPTR(lt_old_ck_padany)(aTHX_ o); @@ -176,8 +192,8 @@ STATIC OP *lt_ck_padany(pTHX_ OP *o) { if (stash && (hint = lt_hint())) { SV *orig_pkg = newSVpvn(HvNAME_get(stash), HvNAMELEN_get(stash)); SV *orig_meth = lt_default_meth; - SV *type_pkg = orig_pkg; - SV *type_meth = orig_meth; + SV *type_pkg = NULL; + SV *type_meth = NULL; SV *code = INT2PTR(SV *, SvUVX(hint)); SvREADONLY_on(orig_pkg); @@ -202,7 +218,6 @@ STATIC OP *lt_ck_padany(pTHX_ OP *o) { croak(__PACKAGE__ " mangler should return zero, one or two scalars, but got %d", items); if (items == 0) { SvREFCNT_dec(orig_pkg); - SvREFCNT_dec(orig_meth); goto skip; } else { SV *rsv; @@ -225,12 +240,19 @@ STATIC OP *lt_ck_padany(pTHX_ OP *o) { LEAVE; } - if (type_meth == orig_meth) + if (!type_pkg) { + type_pkg = orig_pkg; + SvREFCNT_inc(orig_pkg); + } + + if (!type_meth) { + type_meth = orig_meth; SvREFCNT_inc(orig_meth); - lt_map_store(o, orig_pkg, type_pkg, type_meth, lt_old_pp_padsv); + } - lt_old_pp_padsv = PL_ppaddr[OP_PADSV]; - PL_ppaddr[OP_PADSV] = lt_pp_padsv; + lt_pp_padsv_save(); + + lt_map_store(o, orig_pkg, type_pkg, type_meth, lt_pp_padsv_saved); } skip: @@ -240,7 +262,8 @@ skip: STATIC OP *(*lt_old_ck_padsv)(pTHX_ OP *) = 0; STATIC OP *lt_ck_padsv(pTHX_ OP *o) { - PL_ppaddr[OP_PADSV] = lt_old_pp_padsv; + lt_pp_padsv_restore(o); + return CALL_FPTR(lt_old_ck_padsv)(aTHX_ o); } @@ -255,17 +278,17 @@ PROTOTYPES: DISABLE BOOT: { if (!lt_initialized++) { + lt_op_map = ptable_new(); + lt_default_meth = newSVpvn("TYPEDSCALAR", 11); SvREADONLY_on(lt_default_meth); PERL_HASH(lt_hash, __PACKAGE__, __PACKAGE_LEN__); - lt_op_map = newHV(); lt_old_ck_padany = PL_check[OP_PADANY]; PL_check[OP_PADANY] = MEMBER_TO_FPTR(lt_ck_padany); lt_old_ck_padsv = PL_check[OP_PADSV]; PL_check[OP_PADSV] = MEMBER_TO_FPTR(lt_ck_padsv); - lt_old_pp_padsv = PL_ppaddr[OP_PADSV]; } }