Object-Pad

 view release on metacpan or  search on metacpan

include/class.h  view on Meta::CPAN

    /* Things that only roles have */
    struct {
      AV *superroles;      /* each elem is a raw pointer directly to a ClassMeta whose type == METATYPE_ROLE */
      HV *applied_classes; /* keyed by class name each elem is a raw pointer directly to a RoleEmbedding */
      AV *applycvs;        /* the APPLY {} phaser blocks; each elem is a CV* directly */
    } role;
  };
};

/* Metadata about the embedding of a role into a class */
#define LINNET_VAL_ROLEEMBEDDING  0x4F505245  /* "OPRE" */
#define MUST_ROLEEMBEDDING(ptr)   LINNET_CHECK_CAST(ptr, RoleEmbedding *, LINNET_VAL_ROLEEMBEDDING)
typedef struct RoleEmbedding {
  LINNET_FIELD
  SV *embeddingsv;
  struct ClassMeta *rolemeta;
  struct ClassMeta *classmeta;
  PADOFFSET offset;
} RoleEmbedding;

#define LINNET_VAL_METHODMETA  0x4F504D4D  /* "OPMM" */
#define MUST_METHODMETA(ptr)   LINNET_CHECK_CAST(ptr, MethodMeta *, LINNET_VAL_METHODMETA)

lib/Object/Pad.xs  view on Meta::CPAN

    croak("ARGH: Expected that padix[$self] = 1");

  /* Give it a name that isn't valid as a Perl variable so it can't collide */
  padix = pad_add_name_pvs("@(Object::Pad/fields)", 0, NULL, NULL);
  if(padix != PADIX_FIELDS)
    croak("ARGH: Expected that padix[@fields] = 2");

  if(meta->type == METATYPE_ROLE) {
    /* Don't give this a padname or Future::AsyncAwait will break it (RT137649) */
    padix = pad_add_name_pvs("", 0, NULL, NULL);
    if(padix != PADIX_EMBEDDING)
      croak("ARGH: Expected that padix[(embedding)] = 3");
  }
}

static void S_freepadsv(pTHX_ PADOFFSET padix)
{
  SvREFCNT_dec(PAD_SVl(padix));
  PAD_SVl(padix) = NULL;
}
#define SAVEFREEPADSV(padix)  SAVEDESTRUCTOR_X(S_freepadsv, (void *)(padix))

lib/Object/Pad.xs  view on Meta::CPAN

    croak("Cannot invoke method on a non-instance");

  HV *classstash;
  FIELDOFFSET offset;
  RoleEmbedding *embedding = NULL;

  if(is_role) {
    /* Embedding info is stored in pad1; PAD_SVl() will look at CvDEPTH. We'll
     * have to grab it manually */
    PAD *pad1 = PadlistARRAY(CvPADLIST(find_runcv(0)))[1];
    SV *embeddingsv = PadARRAY(pad1)[PADIX_EMBEDDING];

    /* We should never see NULL */
    assert(embeddingsv);

    if(SvTYPE(embeddingsv) == SVt_PVHV) {
      HV *applied_classes = (HV *)embeddingsv;
      HV *stash = SvSTASH(SvRV(self));

      if(stash == CvSTASH(find_runcv(0)))
        croak("Cannot invoke a role method directly");

      AV *isa = mro_get_linear_isa(stash);

      for(UV idx = 0; idx < av_count(isa); idx++) {
        HE *he = hv_fetch_ent(applied_classes, AvARRAY(isa)[idx], 0, 0);
        if(!he)
          continue;

        /* HeVAL is a RoleEmbedding * directly */
        embedding = MUST_ROLEEMBEDDING(HeVAL(he));
        break;
      }

      if(!embedding)
        croak("Could not find embedding info for %" HEKf " in applied classes map",
          HEKfARG(HvNAME_HEK(stash)));
    }
    else {
      embedding = MUST_ROLEEMBEDDING(SvPVX(embeddingsv));
    }

    if(embedding == &ObjectPad__embedding_standalone) {
      classstash = NULL;
      offset     = 0;
    }
    else {
      classstash = embedding->classmeta->stash;
      offset     = embedding->offset;
    }

lib/Object/Pad.xs  view on Meta::CPAN

    while((iter = hv_iternext(parammap))) {
      ParamMeta *parammeta = MUST_PARAMMETA(HeVAL(iter));

      dump_parammeta(aTHX_ ctx, parammeta);
    }
  }

  switch(classmeta->type) {
    case METATYPE_CLASS:
      for(i = 0; i < av_count(classmeta->cls.direct_roles); i++) {
        RoleEmbedding *embedding = MUST_ROLEEMBEDDING(AvARRAY(classmeta->cls.direct_roles)[i]);

        dump_roleembedding(aTHX_ ctx, embedding);
      }
      break;

    case METATYPE_ROLE:
      /* No need to dump the values of role.applied_classes because any class
       * they're applied to will have done that already */
      break;
  }

lib/Object/Pad.xs  view on Meta::CPAN

    retcount++;

    PUTBACK;

    while(classmeta) {
      retcount += deconstruct_object_class(fieldstore, classmeta, 0);

      AV *roles = classmeta->cls.direct_roles;
      U32 nroles = av_count(roles);
      for(U32 i = 0; i < nroles; i++) {
        RoleEmbedding *embedding = MUST_ROLEEMBEDDING(AvARRAY(roles)[i]);

        retcount += deconstruct_object_class(fieldstore, embedding->rolemeta, embedding->offset);
      }

      classmeta = classmeta->cls.supermeta;
    }

    SPAGAIN;
    XSRETURN(retcount);
  }

lib/Object/Pad.xs  view on Meta::CPAN

    while(classmeta) {
      if(!want_classname || sv_eq(want_classname, classmeta->name)) {
        RETVAL = ref_field_class(want_fieldname, fieldstore, classmeta, 0);
        if(RETVAL)
          goto done;
      }

      AV *roles = classmeta->cls.direct_roles;
      U32 nroles = av_count(roles);
      for(U32 i = 0; i < nroles; i++) {
        RoleEmbedding *embedding = MUST_ROLEEMBEDDING(AvARRAY(roles)[i]);

        if(!want_classname || sv_eq(want_classname, embedding->rolemeta->name)) {
          RETVAL = ref_field_class(want_fieldname, fieldstore, embedding->rolemeta, embedding->offset);
          if(RETVAL)
            goto done;
        }
      }

      classmeta = classmeta->cls.supermeta;
    }

share/include/object_pad.h  view on Meta::CPAN


  REPR_PVOBJ,        /* instances are SVt_PVOBJ on perl 5.38+ */
};

/* Special pad indexes within `method` CVs */
enum {
  PADIX_SELF = 1,
  PADIX_FIELDS = 2,

  /* for role methods */
  PADIX_EMBEDDING = 3,

  /* during initfields */
  PADIX_PARAMS = 4,
};

/* Function prototypes */

#define get_compclassmeta()  ObjectPad_get_compclassmeta(aTHX)
ClassMeta *ObjectPad_get_compclassmeta(pTHX);

src/class.c  view on Meta::CPAN

        (void)(PL_cop_seqmax == PERL_PADSEQ_INTRO && PL_cop_seqmax++))
#endif

#define need_PLparser()  ObjectPad__need_PLparser(aTHX)
void ObjectPad__need_PLparser(pTHX); /* in Object/Pad.xs */

/* Empty MGVTBL simply for locating instance backing AV */
static MGVTBL vtbl_backingav = {};

RoleEmbedding ObjectPad__embedding_standalone = {
  LINNET_INIT(LINNET_VAL_ROLEEMBEDDING)
};

typedef struct ClassAttributeRegistration ClassAttributeRegistration;

struct ClassAttributeRegistration {
  ClassAttributeRegistration *next;

  const char *name;
  STRLEN permit_hintkeylen;

src/class.c  view on Meta::CPAN

    }
  }

  if(classmeta->type == METATYPE_CLASS) {
    U32 nroles;
    RoleEmbedding **embeddings = mop_class_get_direct_roles(classmeta, &nroles);

    assert(classmeta->type == METATYPE_CLASS || nroles == 0);

    for(i = 0; i < nroles; i++) {
      RoleEmbedding *embedding = MUST_ROLEEMBEDDING(embeddings[i]);
      ClassMeta *rolemeta = embedding->rolemeta;

      assert(rolemeta->sealed);

      make_instance_fields(rolemeta, fieldstore, embedding->offset);
    }
  }
}

#define alias_fieldkeys_into_av(classmeta, hv, backingav)  S_alias_fieldkeys_into_av(aTHX_ classmeta, hv, backingav)

src/class.c  view on Meta::CPAN


  /* Perl core's cv_clone() would break in some situation here; see
   *   https://rt.cpan.org/Ticket/Display.html?id=141483
   */
  CV *embedded_cv = cv_copy_flags(cv, 0);
  SV *embeddingsv = embedding->embeddingsv;

  assert(SvTYPE(embeddingsv) == SVt_PV && SvLEN(embeddingsv) >= sizeof(RoleEmbedding));

  PAD *pad1 = PadlistARRAY(CvPADLIST(embedded_cv))[1];
  PadARRAY(pad1)[PADIX_EMBEDDING] = SvREFCNT_inc(embeddingsv);

  return embedded_cv;
}

RoleEmbedding *ObjectPad__get_embedding_from_pad(pTHX)
{
  /* Embedding info is stored in pad1; PAD_SVl() will look at CvDEPTH. We'll
   * have to grab it manually */
  PAD *pad1 = PadlistARRAY(CvPADLIST(find_runcv(0)))[1];
  SV *embeddingsv = PadARRAY(pad1)[PADIX_EMBEDDING];
  if(embeddingsv && embeddingsv != &PL_sv_undef)
    return MUST_ROLEEMBEDDING(SvPVX(embeddingsv));
  else
    return NULL;
}

RoleEmbedding **ObjectPad_mop_class_get_direct_roles(pTHX_ const ClassMeta *meta, U32 *nroles)
{
  assert(meta->type == METATYPE_CLASS);
  AV *roles = meta->cls.direct_roles;
  *nroles = av_count(roles);
  return (RoleEmbedding **)AvARRAY(roles);

src/class.c  view on Meta::CPAN

    padix = pad_add_name_pvs("$class", 0, NULL, NULL);
    if(padix != PADIX_SELF)
      croak("ARGH: Expected that padix[$class] = 1");
    intro_my();
  }

  if(meta->type == METATYPE_ROLE) {
    PAD *pad1 = PadlistARRAY(CvPADLIST(PL_compcv))[1];

    if(meta->role_is_invokable) {
      SV *sv = PadARRAY(pad1)[PADIX_EMBEDDING];
      SvUPGRADE(sv, SVt_PV);
      SvPOK_on(sv);
      SvLEN(sv) = 0;
      SvPVX(sv) = (void *)&ObjectPad__embedding_standalone;
    }
    else {
      SvREFCNT_dec(PadARRAY(pad1)[PADIX_EMBEDDING]);
      /* Unembedded role CVs store the entire class map */
      PadARRAY(pad1)[PADIX_EMBEDDING] = SvREFCNT_inc(meta->role.applied_classes);
    }
  }
}

void ObjectPad__add_fields_to_pad(pTHX_ ClassMeta *meta, U32 since_field)
{
  AV *fields = meta->fields;
  U32 nfields = av_count(fields);

  U32 i;

src/class.c  view on Meta::CPAN


    CvOUTSIDE(PL_compcv)     = CvOUTSIDE(outside);
    CvOUTSIDE_SEQ(PL_compcv) = CvOUTSIDE_SEQ(outside);
  }

  return body;
}

void ObjectPad__prepare_adjust_params(pTHX_ ClassMeta *meta)
{
  /* Skip the PADIX_EMBEDDING slot if not already done so */
  if(meta->type != METATYPE_ROLE)
    pad_add_name_pvs("", 0, NULL, NULL);

  PADOFFSET params_padix = pad_add_name_pvs("%(params)", 0, NULL, NULL);
  assert(params_padix == PADIX_PARAMS);
  PERL_UNUSED_VAR(params_padix);

  intro_my();
}

src/class.c  view on Meta::CPAN

}

#define mop_class_implements_role(meta, rolemeta)  S_mop_class_implements_role(aTHX_ meta, rolemeta)
static bool S_mop_class_implements_role(pTHX_ ClassMeta *meta, ClassMeta *rolemeta)
{
  U32 i, n;
  switch(meta->type) {
    case METATYPE_CLASS: {
      RoleEmbedding **embeddings = mop_class_get_all_roles(meta, &n);
      for(i = 0; i < n; i++)
        if(MUST_ROLEEMBEDDING(embeddings[i])->rolemeta == rolemeta)
          return true;

      break;
    }

    case METATYPE_ROLE: {
      ClassMeta **roles = (ClassMeta **)AvARRAY(meta->role.superroles);
      U32 n = av_count(meta->role.superroles);
      /* TODO: this isn't super-efficient in deep cross-linked heirarchies */
      for(i = 0; i < n; i++) {

src/class.c  view on Meta::CPAN


  HV *srcstash = rolemeta->stash;
  HV *dststash = classmeta->stash;

  SV *embeddingsv = newSV(sizeof(RoleEmbedding));
  assert(SvTYPE(embeddingsv) == SVt_PV && SvLEN(embeddingsv) >= sizeof(RoleEmbedding));

  RoleEmbedding *embedding = (RoleEmbedding *)SvPVX(embeddingsv);

  *embedding = (RoleEmbedding){
    LINNET_INIT(LINNET_VAL_ROLEEMBEDDING)
    .embeddingsv = embeddingsv,
    .rolemeta    = rolemeta,
    .classmeta   = classmeta,
    .offset      = -1,
  };

  av_push(classmeta->cls.embedded_roles, (SV *)embedding);
  hv_store_ent(rolemeta->role.applied_classes, classmeta->name, (SV *)embedding, 0);

  U32 nbuilds = rolemeta->buildcvs ? av_count(rolemeta->buildcvs) : 0;

src/class.c  view on Meta::CPAN

    }
  }
}

static void S_apply_roles(pTHX_ ClassMeta *dstmeta, ClassMeta *srcmeta)
{
  U32 nroles;
  RoleEmbedding **arr = mop_class_get_direct_roles(srcmeta, &nroles);
  U32 i;
  for(i = 0; i < nroles; i++) {
    mop_class_apply_role(MUST_ROLEEMBEDDING(arr[i]));
  }
}

void ObjectPad__check_colliding_param(pTHX_ ClassMeta *classmeta, SV *paramname)
{
  HV *parammap = classmeta->parammap;
  assert(parammap);

  HE *he = hv_fetch_ent(parammap, paramname, 0, 0);
  if(!he)

src/class.c  view on Meta::CPAN

  if(meta->initfields_lines) {
    ops = op_append_list(OP_LINESEQ, ops,
      meta->initfields_lines);
  }

  if(meta->type == METATYPE_CLASS) {
    U32 nroles;
    RoleEmbedding **embeddings = mop_class_get_direct_roles(meta, &nroles);

    for(i = 0; i < nroles; i++) {
      RoleEmbedding *embedding = MUST_ROLEEMBEDDING(embeddings[i]);
      ClassMeta *rolemeta = embedding->rolemeta;

      if(!rolemeta->sealed)
        mop_class_seal(rolemeta);

      assert(rolemeta->sealed);
      assert(rolemeta->initfields);

      DEBUG_SET_CURCOP_LINE(__LINE__);

src/class.c  view on Meta::CPAN


    if(!cv_does && meta->cls.foreign_does)
      cv_does = meta->cls.foreign_does;

    if(sv_eq(meta->name, wantrole)) {
      XSRETURN_YES;
    }

    int i;
    for(i = 0; i < nroles; i++) {
      RoleEmbedding *embedding = MUST_ROLEEMBEDDING(AvARRAY(roles)[i]);
      if(sv_eq(embedding->rolemeta->name, wantrole)) {
        XSRETURN_YES;
      }
    }

    meta = meta->type == METATYPE_CLASS ? meta->cls.supermeta : NULL;
  }

  if (cv_does) {
    /* return $self->DOES(@_); */

src/class.c  view on Meta::CPAN

      copy_requiremethods_from(meta, supermeta);

    if(supermeta->has_adjust)
      meta->has_adjust = true;

    U32 nroles;
    RoleEmbedding **embeddings = mop_class_get_all_roles(supermeta, &nroles);
    if(nroles) {
      U32 i;
      for(i = 0; i < nroles; i++) {
        RoleEmbedding *embedding = MUST_ROLEEMBEDDING(embeddings[i]);
        ClassMeta *rolemeta = embedding->rolemeta;

        av_push(meta->cls.embedded_roles, (SV *)embedding);
        hv_store_ent(rolemeta->role.applied_classes, meta->name, (SV *)embedding, 0);
      }
    }
  }
  else {
    /* A subclass of a foreign class */
    meta->cls.foreign_new = fetch_superclass_method_pv(meta->stash, "new", 3, -1);

src/field.c  view on Meta::CPAN

    const char *key = HvNAME(objstash);
    STRLEN klen = HvNAMELEN(objstash);
    if(HvNAMEUTF8(objstash))
      klen = -klen;

    assert(key);
    SV **svp = hv_fetch(classmeta->role.applied_classes, key, klen, 0);
    if(!svp)
      croak("Cannot fetch role field value from a non-applied instance");

    RoleEmbedding *embedding = MUST_ROLEEMBEDDING(*svp);

    fieldstore = get_obj_fieldstore(self, embedding->classmeta->repr, true);
    fieldix = fieldmeta->fieldix + embedding->offset;
  }
  else {
    const char *stashname = HvNAME(classmeta->stash);

    if(!stashname || !sv_derived_from(self, stashname))
      croak("Cannot fetch field value from a non-derived instance");



( run in 1.613 second using v1.01-cache-2.11-cpan-71847e10f99 )