Class-Accessor-Inherited-XS

 view release on metacpan or  search on metacpan

xs/accessors.h  view on Meta::CPAN


/*
    These macroses impose the following rules:
        - SP is at the start of the args list
        - SP may become invalid afterwards, so don't touch it
        - PL_stack_sp is updated when needed

    The latter may be not that obvious, but it's a result of a callback doing
    dirty stack work for us. Note that only essential cleanup is done
    after call_sv().
*/

#define TYPE_INHERITED (type == InheritedCb || type == InheritedCbNamed)

#define PUSH_PAYLOAD_KEY \
    /* METHOD_NAMED path won't give us a free SP slot */ \
    EXTEND(SP, items + 1);                      \
    *(SP += items + 1) = payload->hash_key;     \
    PUTBACK;                                    \
    /*
        re-enable when messing with stack for tests
        assert(PL_curstackinfo->si_stack_hwm >= PL_stack_sp - PL_stack_base);
    */ \


#define CALL_READ_CB(result)                        \
    if (TYPE_INHERITED && payload->read_cb) {  \
        ENTER;                                      \
        PUSHMARK(SP);                               \
        *(SP+1) = sv_2mortal(newSVsv(result));      \
        if (type == InheritedCbNamed) {             \
            PUSH_PAYLOAD_KEY;                       \
        }                                           \
        call_sv(payload->read_cb, G_SCALAR);        \
        LEAVE;                                      \
    } else {                                        \
        *(SP+1) = sv_2mortal(newSVsv(result));      \
    }                                               \

#define CALL_WRITE_CB(slot, need_alloc)             \
    if (TYPE_INHERITED && payload->write_cb) { \
        ENTER;                                      \
        PUSHMARK(SP);                               \
        if (type == InheritedCbNamed) {             \
            PUSH_PAYLOAD_KEY;                       \
        }                                           \
        call_sv(payload->write_cb, G_SCALAR);       \
        SPAGAIN;                                    \
        LEAVE;                                      \
        if (need_alloc) slot = newSV(0);            \
        sv_setsv(slot, *SP);                        \
        *SP = slot;                                 \
    } else {                                        \
        if (need_alloc) slot = newSV(0);            \
        sv_setsv(slot, *(SP+2));                    \
        PUSHs(slot);                                \
        PUTBACK;                                    \
    }                                               \

#define CALL_WRITE_WEAKEN(slot) \
    if (opts & IsWeak) sv_rvweaken(slot)

#define READONLY_TYPE_ASSERT \
    assert(type == Inherited || type == PrivateClass || type == ObjectOnly || type == LazyClass)

#define READONLY_CROAK_CHECK                            \
    if (!TYPE_INHERITED && (opts & IsReadonly)) {   \
        READONLY_TYPE_ASSERT;                           \
        croak("Can't set value in readonly accessor");  \
        return;                                         \
    }                                                   \

#define SET_GVGP_FLAGS(glob, sv)\
    if (SvOK(sv)) {             \
        GvGPFLAGS_on(glob);     \
                                \
    } else {                    \
        GvGPFLAGS_off(glob);    \
        GvLINE(glob) = 0;       \
    }                           \

template <bool overflow> static
SV*
CAIXS_icache_get(pTHX_ HV* stash, GV* glob) {
    const struct mro_meta* stash_meta = HvMROMETA(stash);
    const long long curgen = (long long)PL_sub_generation + stash_meta->pkg_gen;

    if (GvLINE(glob) == curgen || GvGPFLAGS(glob)) return GvSV(glob);
    if (overflow && UNLIKELY(curgen > ((U32)1 << 31) - 1)) {
        warn("MRO cache generation 31 bit wraparound");
        PL_sub_generation = 0;
    }

    return NULL;
}

static SV*
CAIXS_icache_update(pTHX_ HV* stash, GV* glob, SV* pkg_key) {
    AV* supers = mro_get_linear_isa(stash);
    /*
        First entry in the 'mro_get_linear_isa' list is the 'stash' itself.
        It's already been tested, so ajust both counter and iterator to skip over it.
    */
    SSize_t fill     = AvFILLp(supers);
    SV** supers_list = AvARRAY(supers);

    SV* elem;
    SV* result = NULL;

    GV* stack[fill + 1];
#ifdef DEBUGGING
    memzero(stack, (fill + 1) * sizeof(GV*));
#endif
    stack[fill] = glob;

    while (result == NULL && --fill >= 0) {
        elem = *(++supers_list);
        assert(elem); /* mro_get_linear_isa returns dense array */

        HV* next_stash = gv_stashsv(elem, 0);
        /*



( run in 1.223 second using v1.01-cache-2.11-cpan-98e64b0badf )