Affix
view release on metacpan or search on metacpan
lib/Affix/marshal.c view on Meta::CPAN
safefree((void *)raw_ptr);
}
}
}
/* Case 2: alloc_owned() stores ptr directly in a UV scalar */
else if (SvOK(sv)) {
UV raw_ptr = SvUV(sv);
if (raw_ptr) {
sv_setuv(sv, 0);
safefree((void *)raw_ptr);
}
}
}
IV alloc_raw(pTHX_ IV sz) { return PTR2IV(safecalloc(1, sz)); }
void set_mem_u128(IV addr, IV l, IV h) {
unsigned __int128 * p = (unsigned __int128 *)addr;
*p = ((unsigned __int128)h << 64) | (unsigned __int128)l;
}
IV get_string_ptr() {
static char * m = "Hello from C Pointer";
return PTR2IV(m);
}
int test_invoke_callback(IV addr, int a, double b) {
int (*f)(int, double) = (int (*)(int, double))addr;
return f(a, b);
}
/**
* @brief Verifies native callback invocation for 128-bit function pointers.
*/
SV * test_invoke_callback_128(pTHX_ IV addr, SV * arg_sv) {
unsigned __int128 (*f)(__int128) = (unsigned __int128 (*)(__int128))addr;
__int128 arg = (__int128)_alt_sv_to_int128(aTHX_ arg_sv);
unsigned __int128 res = f(arg);
SV * ret = newSV(0);
alt_int128_to_sv(aTHX_ ret, res, false); /* Callback return value is uint128 */
return ret;
}
IV get_file_ptr(pTHX_ SV * fh_ref) {
IO * io = sv_2io(fh_ref);
if (!io)
return 0;
return PTR2IV(PerlIO_exportFILE(IoIFP(io), nullptr));
}
typedef struct {
unsigned __int128 val;
int id;
} BigData;
void mutate_big_data_native(BigData * d) {
d->val += 1; /* Add 1 to the 128-bit int natively */
d->id = 777;
}
void verify_marshalling_128(pTHX_ SV * input) {
dMY_CXT;
const infix_type * type = infix_registry_lookup_type(MY_CXT.registry, "BigData");
BigData stack_struct = {0, 0};
if (SvROK(input)) {
SV * proxy = newSV(0);
sv_setsv(proxy, input);
bind_placeholder(aTHX_ proxy, &stack_struct, type, 0, 0, false, nullptr, nullptr, false, false);
MAGIC * mg = mg_find(proxy, PERL_MAGIC_ext);
if (mg && mg->mg_virtual->svt_set)
mg->mg_virtual->svt_set(aTHX_ proxy, mg);
SvREFCNT_dec(proxy);
}
mutate_big_data_native(&stack_struct);
if (SvROK(input)) {
SV * proxy_rv = bind_aggregate(aTHX_ & stack_struct, type, nullptr, false);
HV * target_hv = (HV *)SvRV(input);
HV * source_hv = (HV *)SvRV(proxy_rv);
hv_iterinit(source_hv);
HE * entry;
while ((entry = hv_iternext(source_hv))) {
I32 klen;
char * kstr = hv_iterkey(entry, &klen);
SV * val = hv_iterval(source_hv, entry);
hv_store(target_hv, kstr, klen, newSVsv(val), 0);
}
SvREFCNT_dec(proxy_rv);
}
}
/* Mock C++ Object For Custom Destructor Test */
typedef struct {
int value;
} MockCxxObj;
static int mock_cxx_dtor_calls = 0;
IV mock_cxx_new(int v) {
MockCxxObj * obj = safemalloc(sizeof(MockCxxObj));
obj->value = v;
return PTR2IV(obj);
}
void mock_cxx_delete(void * ptr) {
mock_cxx_dtor_calls++;
safefree(ptr);
}
IV get_mock_cxx_dtor() { return PTR2IV(mock_cxx_delete); }
int get_mock_cxx_dtor_calls() { return mock_cxx_dtor_calls; }
XS_INTERNAL(XS_main_define_types) {
dVAR;
dXSARGS;
if (items != 1)
croak_xs_usage(cv, "defs");
define_types(aTHX_ SvPV_nolen(ST(0)));
XSRETURN_EMPTY;
}
XS_INTERNAL(XS_main_sizeof_type) {
lib/Affix/marshal.c view on Meta::CPAN
if (items != 0)
croak_xs_usage(cv, "");
{
IV RETVAL;
dXSTARG;
RETVAL = get_string_ptr();
TARGi((IV)RETVAL, 1);
ST(0) = TARG;
}
XSRETURN(1);
}
XS_INTERNAL(XS_main_test_invoke_callback) {
dVAR;
dXSARGS;
if (items != 3)
croak_xs_usage(cv, "addr, a, b");
{
IV addr = (IV)SvIV(ST(0));
int a = (int)SvIV(ST(1));
double b = (double)SvNV(ST(2));
int RETVAL;
dXSTARG;
RETVAL = test_invoke_callback(addr, a, b);
TARGi((IV)RETVAL, 1);
ST(0) = TARG;
}
XSRETURN(1);
}
XS_INTERNAL(XS_main_test_invoke_callback_128) {
dVAR;
dXSARGS;
if (items != 2)
croak_xs_usage(cv, "addr, arg_sv");
{
IV addr = (IV)SvIV(ST(0));
SV * arg_sv = ST(1);
SV * RETVAL;
RETVAL = test_invoke_callback_128(aTHX_ addr, arg_sv);
RETVAL = sv_2mortal(RETVAL);
ST(0) = RETVAL;
}
XSRETURN(1);
}
XS_INTERNAL(XS_main_get_file_ptr) {
dVAR;
dXSARGS;
if (items != 1)
croak_xs_usage(cv, "fh_ref");
{
SV * fh_ref = ST(0);
IV RETVAL;
dXSTARG;
RETVAL = get_file_ptr(aTHX_ fh_ref);
TARGi((IV)RETVAL, 1);
ST(0) = TARG;
}
XSRETURN(1);
}
XS_INTERNAL(XS_main_verify_marshalling_128) {
dVAR;
dXSARGS;
if (items != 1)
croak_xs_usage(cv, "input");
verify_marshalling_128(aTHX_ ST(0));
XSRETURN_EMPTY;
}
XS_INTERNAL(XS_main_mock_cxx_new) {
dVAR;
dXSARGS;
if (items != 1)
croak_xs_usage(cv, "v");
{
int v = (int)SvIV(ST(0));
IV RETVAL;
dXSTARG;
RETVAL = mock_cxx_new(v);
TARGi((IV)RETVAL, 1);
ST(0) = TARG;
}
XSRETURN(1);
}
XS_INTERNAL(XS_main_get_mock_cxx_dtor) {
dVAR;
dXSARGS;
if (items != 0)
croak_xs_usage(cv, "");
{
IV RETVAL;
dXSTARG;
RETVAL = get_mock_cxx_dtor();
TARGi((IV)RETVAL, 1);
ST(0) = TARG;
}
XSRETURN(1);
}
XS_INTERNAL(XS_main_mock_cxx_delete) {
dVAR;
dXSARGS;
if (items != 1)
croak_xs_usage(cv, "ptr");
mock_cxx_delete(INT2PTR(void *, SvIV(ST(0))));
XSRETURN_EMPTY;
}
XS_INTERNAL(XS_main_get_mock_cxx_dtor_calls) {
dVAR;
dXSARGS;
if (items != 0)
croak_xs_usage(cv, "");
{
int RETVAL;
dXSTARG;
RETVAL = get_mock_cxx_dtor_calls();
TARGi((IV)RETVAL, 1);
ST(0) = TARG;
}
XSRETURN(1);
}
/**
* @brief Helper to verify if a VTable belongs to the Affix system (v1 or v2).
*/
int is_v2_vtable(MGVTBL * v) {
if (!v)
return 0;
return (v == &vtbl_sint8 || v == &vtbl_uint8 || v == &vtbl_sint16 || v == &vtbl_uint16 || v == &vtbl_sint32 ||
v == &vtbl_uint32 || v == &vtbl_sint64 || v == &vtbl_uint64 || v == &vtbl_sint128 || v == &vtbl_uint128 ||
v == &vtbl_float || v == &vtbl_double || v == &vtbl_float16 || v == &vtbl_bool || v == &vtbl_void ||
v == &vtbl_bitfield || v == &vtbl_pointer || v == &vtbl_array || v == &string_vtable ||
v == &wstring_vtable || v == &vtbl_lazy_aggregate || v == &vtbl_enum || v == &vtbl_buffer);
}
/**
* @brief Internal helper to safely extract a pointer address from a Perl scalar.
* @details This function handles Affix::Memory objects, v2.0 magical Pins, and
* raw integers. It includes logic to handle Pointer[Void] correctly by
* suppressing the dereference that is normally required for typed pointers.
*
* @param sv The Perl Scalar to inspect.
* @param ignore_mg A specific magic pointer to skip (prevents self-extraction during assignment).
* @return The raw C pointer address, or NULL if extraction fails.
*/
void * _extract_pointer_value(pTHX_ SV * sv, MAGIC * ignore_mg) {
if (!sv)
return nullptr;
// Use a secondary pointer for unwrapping to preserve the original SV (the potential object)
SV * target = sv;
if (SvROK(sv))
target = SvRV(sv);
/* Handle Magic Pins (even inside blessed objects) */
if (SvMAGICAL(target)) {
MAGIC * mg = mg_find(target, PERL_MAGIC_ext);
while (mg) {
if (is_v2_vtable(mg->mg_virtual) && mg != ignore_mg) {
Affix_Pin_2_Point_Oh * im = (Affix_Pin_2_Point_Oh *)mg->mg_ptr;
if (mg->mg_virtual == &vtbl_pointer)
return im->absolute ? im->ptr : (im->ptr ? *(void **)im->ptr : nullptr);
return im->ptr;
}
mg = mg->mg_moremagic;
}
}
/* Handle Affix::Memory Handles */
if (sv_isobject(sv) && sv_derived_from(sv, "Affix::Memory")) {
SV * rv = SvRV(sv);
if (SvTYPE(rv) == SVt_PVAV) {
SV ** p = av_fetch((AV *)rv, 0, 0);
return (p && *p) ? INT2PTR(void *, SvUV(*p)) : nullptr;
}
return INT2PTR(void *, SvUV(rv));
}
/* Fallback: Raw Integers */
if (SvIOK(sv))
return INT2PTR(void *, SvUV(sv));
return nullptr;
}
( run in 0.804 second using v1.01-cache-2.11-cpan-9789f410c06 )