Skip to content
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

Perl_op_convert_list: Avoid unnecessary processing of CONST OPs #22116

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

Conversation

richardleach
Copy link
Contributor

When Perl_op_convert_list is called to stringify a CONST OP, a fair amount
of activity occurs in order to return either an unchanged (if called without the
OPf_FOLDED flag) or only slightly changed (with OPf_FOLDED) OP.

In these commits, any changes are done directly and the CONST OP returned
without wrapping it in a new list OP and constant-folding it back again.

Please note: This almost certainly should be a defer-next-dev PR!

@tonycoz tonycoz added the defer-next-dev This PR should not be merged yet, but await the next development cycle label Apr 2, 2024
@tonycoz
Copy link
Contributor

tonycoz commented Apr 2, 2024

The change looks reasonable, but the added folding code doesn't execute much, from coverage testing against make test_harness:

 13511958: 5535:    if (type == OP_STRINGIFY && OP_TYPE_IS(o, OP_CONST) ) {
        -: 5536:        /* Don't wrap a single CONST in a list, process that list,
        -: 5537:         * then constant fold the list back to the starting OP. */
        -: 5538:        assert(!OpSIBLING(o));
        -: 5539:
  2208678: 5540:        if (flags & OPf_FOLDED) {
      167: 5541:            o->op_folded = 1;
      167: 5542:            SV *sv = cSVOPx_sv(o);
        -: 5543:
      167: 5544:            if (SvPOK(sv))
      165: 5545:                SvFLAGS(sv) |= SVs_PADTMP;
        -: 5546:            else {
        2: 5547:                SV *newsv = newSV_type(SVt_PV);
        2: 5548:                SvFLAGS(newsv) |= SVs_PADTMP;
        2: 5549:                sv_copypv_nomg(newsv, sv);
        2: 5550:                SvFLAGS(newsv) |= (SVf_READONLY|SVf_PROTECT);
        2: 5551:                SvREFCNT_dec_NN(sv);
        -: 5552:#ifdef USE_ITHREADS
        -: 5553:                if (cSVOPx(o)->op_sv) {
        -: 5554:                    cSVOPx(o)->op_sv = newsv;
        -: 5555:                } else {
        -: 5556:                    PAD_SVl((o)->op_targ) = newsv;
        -: 5557:                }
        -: 5558:#else
        2: 5559:                cSVOPx(o)->op_sv = newsv;
        -: 5560:#endif
        -: 5561:            }
        -: 5562:        }
  2208678: 5563:        return o;
        -: 5564:
        -: 5565:    }
 11303280: 5566:    if (!o || o->op_type != OP_LIST)

@richardleach
Copy link
Contributor Author

Thanks for looking at this, @tonycoz.

but the added folding code doesn't execute much

In that case, I'll remove the folding code and add in an extra comment about its absence.

How did you generate that coverage report please?

When Perl_op_convert_list is called to stringify a CONST OP, but the
`op_folded` flag has not been passed in, a fair amount of activity
occurs before the function returns the original CONST OP unchanged.
After this commit, the CONST OP is returned directly.

For example, prior to this commit, given the statement 'print "2\n',
the function is passed a simple CONST OP:

1    const SVOP(0x55c99432c0b8) ===> [SELF]
     PARENT ===> [0x0]
     FLAGS = (SCALAR,SLABBED)
     SV = PV("2\n"\0)

List context is forced upon it to yield:

2    list LISTOP(0x55c99432c048) ===> [0x0]
     PARENT ===> [0x0]
     FLAGS = (UNKNOWN,KIDS,SLABBED)
     |
3    +--pushmark OP(0x55c99432c088) ===> [SELF]
     |   FLAGS = (SCALAR,SLABBED,MORESIB)
     |
1    +--const SVOP(0x55c99432c0b8) ===> [SELF]
         FLAGS = (SCALAR,SLABBED)
         SV = PV("2\n"\0)

The pushmark is nullified and the parent type set:

2    stringify LISTOP(0x55c99432c048) ===> [0x0]
     PARENT ===> [0x0]
     FLAGS = (UNKNOWN,KIDS,SLABBED)
     |
3    +--null (ex-pushmark) OP(0x55c99432c088) ===> [SELF]
     |   FLAGS = (SCALAR,SLABBED,MORESIB)
     |
1    +--const SVOP(0x55c99432c0b8) ===> [SELF]
         FLAGS = (SCALAR,SLABBED)
         SV = PV("2\n"\0)

CHECKOP sets the number of non-null KIDS for the stringify:

2    stringify LISTOP(0x55c99432c048) ===> [0x0]
     PARENT ===> [0x0]
     FLAGS = (UNKNOWN,KIDS,SLABBED)
     PRIVATE = (0x1)
     |
3    +--null (ex-pushmark) OP(0x55c99432c088) ===> [SELF]
     |   FLAGS = (SCALAR,SLABBED,MORESIB)
     |
1    +--const SVOP(0x55c99432c0b8) ===> [SELF]
         FLAGS = (SCALAR,SLABBED)
         SV = PV("2\n"\0)

Then it is constant folded back to:

1    const SVOP(0x55c99432c0b8) ===> [SELF]
     PARENT ===> [0x0]
     FLAGS = (SCALAR,SLABBED)
     SV = PV("2\n"\0)
@richardleach
Copy link
Contributor Author

I'll remove the folding code and add in an extra comment about its absence.

Now done.

@tonycoz
Copy link
Contributor

tonycoz commented Apr 3, 2024

How did you generate that coverage report please?

I built perl following the instructions under "GCC gcov profiling" in perlhacktips, then:

  • make test_harness
  • gcov op.c

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
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.

None yet

2 participants