I'm trying to understand how morph works. perlscalar's morph looks like this:

    void morph (INTVAL type) {
        if (SELF->vtable->base_type == type)
            return;
        if (SELF->vtable->base_type == enum_class_PerlString) {
            PObj_custom_mark_CLEAR(SELF);
            SELF->vtable = Parrot_base_vtables[type];
            return;
        }
        if (type == enum_class_PerlString) {
            /*
             * if we morph to a string, first clear str_val
             * so that after changing the vtable a parallel
             * reader doesn't get a gargabe pointer
             */
            PMC_str_val(SELF) = NULL;
            PObj_custom_mark_SET(SELF);
            SELF->vtable = Parrot_base_vtables[type];
            return;
        }
        if (type == enum_class_BigInt || type == enum_class_Complex) {
            PMC_str_val(SELF) = NULL;
            SELF->vtable = Parrot_base_vtables[type];
            DYNSELF.init();
            return;
        }
        SELF->vtable = Parrot_base_vtables[type];
    }


I think that there are 2 bugs here

1: Morphing from enum_class_PerlString to enum_class_BigInt or
enum_class_Complex looks broken. The return in the second if clause will
quit the function and the DYNSELF.init() will never get called.

Can anyone easily write a regression test that demonstrates this

I think that the cure is to remove

            SELF->vtable = Parrot_base_vtables[type];
            return;

An optimisation on top would be to change the following

        if (type == enum_class_PerlString) {

to

        else if (type == enum_class_PerlString) {



2: The code isn't thread safe, even though it thinks that it is:

        if (type == enum_class_PerlString) {
            /*
             * if we morph to a string, first clear str_val
             * so that after changing the vtable a parallel
             * reader doesn't get a gargabe pointer
             */
            PMC_str_val(SELF) = NULL;
            PObj_custom_mark_SET(SELF);
            SELF->vtable = Parrot_base_vtables[type];
            return;
        }


I see no write barrier. There's no reason why on a dual CPU machine the
parallel reader doesn't see the writes to memory in the order:


            SELF->vtable = Parrot_base_vtables[type];
            PMC_str_val(SELF) = NULL;

and manage go SEGV between the two.

Nicholas Clark

Reply via email to