lucy-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Marvin Humphrey <>
Subject [lucy-dev] Have Clownfish::Obj extend Perl SV
Date Tue, 09 Apr 2013 22:57:07 GMT

I'm thinking about trying out an experiment on a new git branch,
`cfish-obj-as-perl-sv`.  So you folks know where I'm going with this when the
commit emails start coming in, here's the idea...

Here's the struct layout for our current base object, Clownfish::Obj:

    struct cfish_Obj {
        cfish_VTable *vtable;
        union { void *host_obj; int32_t count; } ref;

Python objects start out like so (in non-debugging builds):

    struct PyObject {
        Py_ssize_t    ob_refcnt;
        PyTypeObject *ob_type;

For our Python build, I'd like Clownfish::Obj to extend PyObject.

    struct cfish_Obj {
        Py_ssize_t    ob_refcnt;
        PyTypeObject *ob_type;
        cfish_VTable *vtable;

Making this change will allow any Clownfish object to be used in a PyObject
context.  The refcount will be shared.

Similarly, in our Perl build, I'd like Clownfish::Obj to extend Perl's SV.

    struct cfish_Obj {
        void *sv_any;
        U32   sv_refcnt;
        U32   sv_flags;
        union { void *ptr; IV iv; } sv_union;
        cfish_VTable *vtable;

The motivations for this experiment are:

*   If possible, ditch our current refcounting/host-object-caching mechanism,
    which is kludgy and hard to explain.
*   Reduce per-object memory costs and make those costs more predictable.
    Right now costs are small until we cache a host object -- which
    unfortunately means that memory costs can grow unexpectedly if a large
    number of small objects suddenly gain a cached host object.

Some brainstorming code which might potentially end up in perl/xs/XSBind.c is
below.  There are some issues which need to be solved regarding immutable
objects (such as VTables) and refcounting, but the current system has worse
bugs. :)

I'm not sure whether this experiment is going to work out, but I didn't want
to do too much work in isolation before bringing it to the dev list.

Marvin Humphrey

cfish_VTable_make_obj(cfish_VTable *self) {

    // Allocate an empty, undef SV but with a greater size.
    char *raw;
    Newxz(raw, self->obj_alloc_size, char);  // Newxz to memzero object.
    SV *obj_as_sv       = (SV*)raw;
    SvREFCNT(obj_as_sv) = 1;
    SvANY(obj_as_sv)    = 0;
    SvFLAGS(obj_as_sv)  = 0;

    // Make the object into an inner Perl object SV.
    SvUPGRADE(obj_as_sv, SVt_PVMG);
    sv_setiv(obj_as_sv, PTR2IV(obj_as_sv));  // circular ref not a problem

    // Connect class association.
    // TODO: cache stash pointer as a member of the VTable.
    cfish_CharBuf *class_name = Cfish_VTable_Get_Name(self);
    HV *stash = gv_stashpvn((char*)Cfish_CB_Get_Ptr8(class_name),
                            Cfish_CB_Get_Size(class_name), TRUE);
    SvSTASH_set(obj_as_sv, (HV*)SvREFCNT_inc(stash));

    // Add Clownfish VTable pointer.
    cfish_Obj *obj = (cfish_Obj*)obj_as_sv;
    obj->vtable = self;

    return obj;

cfish_Obj_get_refcount(cfish_Obj *self) {
    return SvREFCNT((SV*)self);

cfish_Obj_inc_refcount(cfish_Obj *self) {
    return self;

cfish_Obj_dec_refcount(cfish_Obj *self) {
    modified_refcount = SvREFCNT((SV*)self->ref.host_obj) - 1;
    // If the SV's refcount falls to 0, DESTROY will be invoked from
    // Perl-space.
    return modified_refcount;

cfish_Obj_to_host(cfish_Obj *self) {
    return newRV_inc((SV*)self);

cfish_Obj_destroy(cfish_Obj *self) {
    // no-op, because Perl is going to take care of freeing `self`.

View raw message