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 )