Skip to content

class.c: clean up any state if we don't finish the class #22374

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: blead
Choose a base branch
from

Conversation

tonycoz
Copy link
Contributor

@tonycoz tonycoz commented Jul 4, 2024

Fixes #22169

@tonycoz tonycoz requested a review from leonerd July 4, 2024 00:22
@tonycoz tonycoz force-pushed the 22169-class-cleanup branch from 977ed47 to 177bd8b Compare July 8, 2024 00:29
@jkeenan jkeenan added the class Issues related to 'class' keyword or __CLASS__ label Jul 9, 2024
@jkeenan
Copy link
Contributor

jkeenan commented Aug 26, 2024

@leonerd, could you please review this p.r. from @tonycoz? Thanks.

struct xpvhv_aux *aux = HvAUX(stash);

SvREFCNT_dec(aux->xhv_class_superclass);
aux->xhv_class_superclass = NULL;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest lifting the pointers to a C autos, and setting struct field to NULL, then call SvREFCNT_dec. Analyse if SvREFCNT_dec_NN is appropriate.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

xhv_class_superclass can be NULL if the class has no base class defined.

I don't think there's any value re-ordering here, since we only write to xhv_class_superclass after the REFCNT_dec.

I think it's unlikely the cache line will expire - this is a reference to an existing class, so it's just going to reduce the reference count and test it.

class.c Outdated
if (SvTYPE(entry) == SVt_PVGV
&& (cv = GvCV((GV*)entry))
&& (CvIsMETHOD(cv) || memEQs(kpv, klen, "new"))) {
SvREFCNT_dec(cv);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add _NN(), cv already proved to be derefable

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

}
else if (SvTYPE(entry) == SVt_PVCV
&& (CvIsMETHOD((CV*)entry) || memEQs(kpv, klen, "new"))) {
(void)hv_delete(stash, kpv, HeUTF8(he) ? -(I32)klen : (I32)klen,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pass the HEK* maybe, or U32 hash. hv_delete_ent() maybe??? XS api is not fully there for exotic with HEK with hash, not fetch, HV operations.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hv_delete_ent() would require making a SV, this would only be efficient for the (I think) atypical case of the key being an SVKEY.

class.c Outdated

/* remove any ISA entries */
SV *isaname = newSVpvf("%" HEKf "::ISA", HvNAME_HEK(stash));
sv_2mortal(isaname);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sv_2mortal(isaname); to isaname = sv_2mortal(isaname);, use the free retval register.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

newSVOP(OP_CONST, 0, (SV *)superaux->xhv_class_initfields_cv),
NULL);
U32 fieldix = PadnameFIELDINFO(pn)->fieldix;
(void)hv_store_ent(fieldix_to_padix, sv_2mortal(newSVuv(fieldix)), newSVuv(padix), 0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a better way of doing this other than a trip through SvPV(3args)'s S_uiv_2buf(), or worse going to libc sprintf with dozens of lock aq/releases, and maybe some kernel calls to the FS. I would just have 4 byte / 8 byte UVs stored straight as raw unprintable binary with SvPOK_on(). Hash algo/perl just sees char strings, vs turning them into longer less dense ascii bytes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code was only re-indented

HE *he;
if((he = hv_fetch_ent(fieldix_to_padix, sv_2mortal(newSVuv(fieldix)), 0, 0)) &&
SvOK(HeVAL(he))) {
fieldop->op_targ = SvUV(HeVAL(he));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

factor out HeVAL(he), get the SV*. its too many layers deep of derefs in code, and probably does optimize, but its 3 or 4 derefs now from the C auto. if accidents happen with multi eval, they will be smaller.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code was only re-indented

fieldop->op_private = op_priv;

HE *he;
if((he = hv_fetch_ent(fieldix_to_padix, sv_2mortal(newSVuv(fieldix)), 0, 0)) &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

idk if this is a loop, but if it is, y not reuse the sv_2mortal(newSVuv()); ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is a loop, but this code was only re-indented.

@jkeenan
Copy link
Contributor

jkeenan commented Mar 19, 2025

@tonycoz do you have a feeling for whether or not we're going to be able to merge this pull request into blead in this dev cycle or not? If not, then I recommend we label it 'defer-next-dev'.

@tonycoz tonycoz added the defer-next-dev This PR should not be merged yet, but await the next development cycle label Mar 19, 2025
@tonycoz
Copy link
Contributor Author

tonycoz commented Mar 19, 2025

It's not going anywhere until @leonerd looks at it

@ap
Copy link
Contributor

ap commented Apr 24, 2025

@leonerd Ping?

field $x = "First";
field $w :reader;
ADJUST {
fail("ADJUST from failed class definition called");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likely wants to be ::fail()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed, thanks.

Copy link
Contributor

@leonerd leonerd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code addition looks fine.
I haven't read in detail the large changes to Perl_class_seal_stash() but I presume this is mostly just a re-indentation exercise with no change besides invoking the new cleanup function in the failure case.

I have read the new .t file about four times and I imagine it's supposed to invoke a compiletime error in the eval STR but I can't see what the error is supposed to be. Could it be made clearer there?

@tonycoz
Copy link
Contributor Author

tonycoz commented Apr 27, 2025

I haven't read in detail the large changes to Perl_class_seal_stash() but I presume this is mostly just a re-indentation exercise with no change besides invoking the new cleanup function in the failure case.

Yes, Except for some re-wrapping it's just indentation, the github diff viewer has an option to ignore whitespace which is handy for changes like this:

image

@tonycoz
Copy link
Contributor Author

tonycoz commented Apr 27, 2025

I have read the new .t file about four times and I imagine it's supposed to invoke a compiletime error in the eval STR but I can't see what the error is supposed to be. Could it be made clearer there?

There's no closing }, I'll add a comment.

@tonycoz tonycoz force-pushed the 22169-class-cleanup branch from c4e20ea to 32bd2da Compare April 28, 2025 00:18
@tonycoz
Copy link
Contributor Author

tonycoz commented Apr 28, 2025

Squashed the two commits since it didn't seem worth messing with adding to the first commit and dealing with the conflicts in moving the code to the new function.

Copy link
Contributor

@leonerd leonerd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, that test makes sense now. LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
class Issues related to 'class' keyword or __CLASS__ defer-next-dev This PR should not be merged yet, but await the next development cycle
Projects
None yet
Development

Successfully merging this pull request may close these issues.

perl cannot recover from failed class definitions (use feature "class";)
6 participants