Skip to content
This repository was archived by the owner on Jun 1, 2023. It is now read-only.

Commit 41cc6cc

Browse files
committed
inline: add op_clone_optree
walk the ops as tree, not via the unreliable op_next UNTESTED
1 parent 05fe4d3 commit 41cc6cc

File tree

4 files changed

+151
-36
lines changed

4 files changed

+151
-36
lines changed

embed.fnc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1287,7 +1287,7 @@ sM |OP* |op_clone_sv |NN OP* o
12871287
: Used in op.c, pp_hot.c, and universal.c
12881288
#if defined(USE_CPERL)
12891289
XEp |void |arg_check_type_sv |NULLOK const PADNAME* pn|NN SV* sv|NULLOK GV *cvname
1290-
AMRp |OP* |op_clone_oplist|NN OP* o |NULLOK OP* last|bool init
1290+
AMRp |OP* |op_clone_optree|NN OP* o |bool init
12911291
#endif
12921292
: Used in op.c and pp_sys.c
12931293
p |int |mode_from_discipline |NULLOK const char* s|STRLEN len

embed.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,7 @@
566566
#define op_append_list(a,b,c) Perl_op_append_list(aTHX_ a,b,c)
567567
#define op_class(a) Perl_op_class(aTHX_ a)
568568
#define op_clone_oplist(a,b,c) Perl_op_clone_oplist(aTHX_ a,b,c)
569+
#define op_clone_optree(a,b) Perl_op_clone_optree(aTHX_ a,b)
569570
#define op_contextualize(a,b) Perl_op_contextualize(aTHX_ a,b)
570571
#define op_convert_list(a,b,c) Perl_op_convert_list(aTHX_ a,b,c)
571572
#define op_dump(a) Perl_op_dump(aTHX_ a)

op.c

Lines changed: 142 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -10884,7 +10884,9 @@ Perl_newFOROP(pTHX_ I32 flags, OP *sv, OP *expr, OP *block, OP *cont)
1088410884
if (SvIV(rightsv)-SvIV(leftsv) <= PERL_MAX_UNROLL_LOOP_COUNT) {
1088510885
DEBUG_kv(Perl_deb(aTHX_ "TODO unroll loop (%" IVdf "..%" IVdf ")\n",
1088610886
SvIV(leftsv), SvIV(rightsv)));
10887-
/* TODO easy with op_clone_oplist from feature/gh23-inline-subs|feature/gh311-opclone */
10887+
/* TODO use op_clone_optree, check the block body for itersv.
10888+
hard-code assignments to the itersv.
10889+
*/
1088810890
}
1088910891
#endif
1089010892
optype = OP_ITER_LAZYIV;
@@ -11556,6 +11558,26 @@ S_op_fixup(pTHX_ OP *old, OP *newop, U32 init) {
1155611558
return NULL;
1155711559
}
1155811560

11561+
#define FIXUP(oa,field) \
11562+
if (((oa*)o)->op_##field) \
11563+
op_fixup(((oa*)o)->op_##field, ((oa*)clone)->op_##field, pass2+2)
11564+
11565+
#define OPCLONE(oa) \
11566+
if (!pass2) { \
11567+
NewOpSz(1102,clone,sizeof(oa)); \
11568+
if (!clone->op_slabbed) { \
11569+
memcpy(clone, o, sizeof(oa)); \
11570+
clone->op_slabbed = 0; \
11571+
} else { \
11572+
memcpy(clone, o, sizeof(oa)); \
11573+
} \
11574+
op_fixup(o, clone, 0); \
11575+
} else { \
11576+
clone = op_fixup(o, NULL, 4); \
11577+
} \
11578+
if (o->op_sibparent) \
11579+
op_fixup(o->op_sibparent, clone->op_sibparent, pass2+2)
11580+
1155911581
/*
1156011582
=for apidoc op_clone_oplist
1156111583

@@ -11564,7 +11586,8 @@ This is the opposite to C<cv_clone>, which clones that pads, but not the ops.
1156411586
If C<last> == NULL, clones the whole sub (i.e. tree), otherwise until C<last>.
1156511587

1156611588
Relinks all ops inside this list, but not the ones outside.
11567-
TODO: Walking by list will miss op_other LOGOP branches.
11589+
TODO: Walking by list will miss op_other LOGOP branches. See rpeep
11590+
for the other logic.
1156811591
We really should walk the tree (first, sibling).
1156911592

1157011593
In the first pass visit and store all op_next pointers, and
@@ -11591,26 +11614,6 @@ Perl_op_clone_oplist(pTHX_ OP* o, OP* last, bool init) {
1159111614

1159211615
op_fixup(NULL, NULL, init?1:0); /* init the fixup cache */
1159311616

11594-
#define FIXUP(oa,field) \
11595-
if (((oa*)o)->op_##field) \
11596-
op_fixup(((oa*)o)->op_##field, ((oa*)clone)->op_##field, pass2+2)
11597-
11598-
#define OPCLONE(oa) \
11599-
if (!pass2) { \
11600-
NewOpSz(1102,clone,sizeof(oa)); \
11601-
if (!clone->op_slabbed) { \
11602-
memcpy(clone, o, sizeof(oa)); \
11603-
clone->op_slabbed = 0; \
11604-
} else { \
11605-
memcpy(clone, o, sizeof(oa)); \
11606-
} \
11607-
op_fixup(o, clone, 0); \
11608-
} else { \
11609-
clone = op_fixup(o, NULL, 4); \
11610-
} \
11611-
if (o->op_sibparent) \
11612-
op_fixup(o->op_sibparent, clone->op_sibparent, pass2+2)
11613-
1161411617
/* first pass: fixup and record all the next pointers, in exec order.
1161511618
second pass: the rest first, sibling, last, ... all pointers are now known */
1161611619
for (pass2=0; pass2<2; pass2++) {
@@ -11659,9 +11662,6 @@ Perl_op_clone_oplist(pTHX_ OP* o, OP* last, bool init) {
1165911662
case OA_SVOP:
1166011663
OPCLONE(SVOP);
1166111664
break;
11662-
/*case OA_PADOP:
11663-
OPCLONE(PADOP);
11664-
break;*/
1166511665
case OA_PVOP_OR_SVOP:
1166611666
OPCLONE(PVOP);
1166711667
break;
@@ -11689,6 +11689,117 @@ Perl_op_clone_oplist(pTHX_ OP* o, OP* last, bool init) {
1168911689
}
1169011690
}
1169111691
}
11692+
return first;
11693+
}
11694+
11695+
/*
11696+
=for apidoc op_clone_optree
11697+
11698+
Clones just the op tree/graph, not the data.
11699+
This is the opposite to C<cv_clone>, which clones that pads, but not the ops,
11700+
and different to L</op_clone_oplist>, which walks just the list of op_next pointers.
11701+
11702+
Relinks all ops inside this list, but not the ones outside.
11703+
11704+
In the first pass visit and store all op_next pointers, and
11705+
store all the locations of the to be fixed up other pointers,
11706+
in the 2nd pass all pointers inside the graph are known, and
11707+
fixup the missing other pointers.
11708+
11709+
C<init> = TRUE will re-initialize the op cache.
11710+
11711+
Note that when op_clone_oplist is called outside of the first compiler
11712+
passes, the ops will not be slabbed. The third rpeep pass is already
11713+
to late.
11714+
11715+
=cut
11716+
*/
11717+
11718+
OP*
11719+
Perl_op_clone_optree(pTHX_ OP* o, bool init) {
11720+
OP *clone = NULL, *prev = NULL, * first = NULL;
11721+
int pass2;
11722+
PERL_ARGS_ASSERT_OP_CLONE_OPTREE;
11723+
11724+
op_fixup(NULL, NULL, init?1:0); /* init the fixup cache */
11725+
11726+
/* first pass: fixup and record all the next pointers, in exec order.
11727+
second pass: the rest first, sibling, last, ... all pointers are now known */
11728+
for (pass2=0; pass2<2; pass2++) {
11729+
for (; o; o = OpSIBLING(o)) {
11730+
switch (OpCLASS(o->op_type)) {
11731+
case OA_BASEOP:
11732+
OPCLONE(OP);
11733+
break;
11734+
case OA_UNOP:
11735+
case OA_BASEOP_OR_UNOP:
11736+
case OA_FILESTATOP:
11737+
case OA_LOOPEXOP:
11738+
OPCLONE(UNOP);
11739+
FIXUP(UNOP,first);
11740+
break;
11741+
case OA_UNOP_AUX:
11742+
OPCLONE(UNOP_AUX);
11743+
FIXUP(UNOP,first);
11744+
break;
11745+
case OA_BINOP:
11746+
OPCLONE(BINOP);
11747+
FIXUP(BINOP,first);
11748+
FIXUP(BINOP,last);
11749+
break;
11750+
case OA_LISTOP:
11751+
OPCLONE(LISTOP);
11752+
FIXUP(LISTOP,first);
11753+
FIXUP(LISTOP,last);
11754+
break;
11755+
case OA_LOGOP:
11756+
OPCLONE(LOGOP);
11757+
FIXUP(LOGOP,first);
11758+
FIXUP(LOGOP,other);
11759+
break;
11760+
case OA_PMOP:
11761+
OPCLONE(PMOP);
11762+
FIXUP(PMOP,first);
11763+
FIXUP(PMOP,last);
11764+
break;
11765+
case OA_METHOP: /* 14 */
11766+
OPCLONE(METHOP);
11767+
if (o->op_private & 1) {
11768+
FIXUP(METHOP,u.op_first); /* dynamic */
11769+
}
11770+
break;
11771+
case OA_SVOP:
11772+
OPCLONE(SVOP);
11773+
break;
11774+
case OA_PVOP_OR_SVOP:
11775+
OPCLONE(PVOP);
11776+
break;
11777+
case OA_LOOP:
11778+
OPCLONE(LOOP);
11779+
FIXUP(LOOP,first);
11780+
FIXUP(LOOP,last);
11781+
FIXUP(LOOP,redoop);
11782+
FIXUP(LOOP,nextop);
11783+
FIXUP(LOOP,lastop);
11784+
break;
11785+
case OA_COP:
11786+
OPCLONE(COP);
11787+
break;
11788+
11789+
default:
11790+
assert(0 && !"op_clone_optree: missing OA_CLASS case");
11791+
}
11792+
if (!pass2) {
11793+
if (prev)
11794+
prev->op_next = clone;
11795+
else
11796+
first = clone;
11797+
prev = clone;
11798+
}
11799+
}
11800+
if (OpKIDS(o))
11801+
o = OpFIRST(o);
11802+
}
1169211803
#undef OPCLONE
1169311804
#undef FIXUP
1169411805
return first;
@@ -11824,7 +11935,7 @@ S_cv_do_inline(pTHX_ OP *o, OP *cvop, CV *cv, bool meth)
1182411935
/* we need to clone the optree, as we most likely change the state and args.
1182511936
Note: cv_clone is useless for us. It clones the pad, but not
1182611937
the ops. We need to keep the pads, but clone the ops. */
11827-
o = op_clone_oplist(CvSTART(cv), NULL, TRUE);
11938+
o = op_clone_optree(CvROOT(cv), TRUE);
1182811939
firstop = o;
1182911940
/* XXX! walking by list will miss op_other LOGOP branches.
1183011941
we really should walk the tree (first-sibling) */
@@ -20540,14 +20651,6 @@ S_peep_leaveloop(pTHX_ BINOP* leave, OP* from, OP* to)
2054020651
if (IS_CONST_OP(from) && IS_CONST_OP(to)
2054120652
&& SvIOK(fromsv = cSVOPx_sv(from)) && SvIOK(tosv = cSVOPx_sv(to)))
2054220653
{
20543-
#ifdef DEBUGGING
20544-
/* Unrolling is easier in newFOROP? */
20545-
if (SvIV(tosv)-SvIV(fromsv) <= PERL_MAX_UNROLL_LOOP_COUNT) {
20546-
DEBUG_kv(Perl_deb(aTHX_ "rpeep: possibly unroll loop (%" IVdf "..%" IVdf ")\n",
20547-
SvIV(fromsv), SvIV(tosv)));
20548-
/* TODO op_clone_oplist from feature/gh23-inline-subs|feature/gh311-opclone */
20549-
}
20550-
#endif
2055120654
/* 2. Check all aelem if can aelem_u */
2055220655
maxto = SvIV(tosv);
2055320656
}
@@ -23520,7 +23623,7 @@ S_add_isa_fields(pTHX_ HV* klass, AV* isa)
2352023623
char *key;
2352123624
I32 klen;
2352223625
/* wrong pad? */
23523-
if (po > AvFILLp(comppad) || !pn)
23626+
if (po > AvFILLp(PL_comppad) || !pn)
2352423627
continue;
2352523628
key = PadnamePV(pn);
2352623629
if (!key)
@@ -23725,6 +23828,10 @@ S_add_does_methods(pTHX_ HV* klass, AV* does)
2372523828
CvGV_set(ncv, sym);
2372623829

2372723830
CvSTASH_set(ncv, klass);
23831+
CvROOT(ncv) = op_clone_optree(CvROOT(cv), TRUE);
23832+
CvSTART(ncv) = LINKLIST(CvROOT(ncv));
23833+
if (CvHASSIG(cv))
23834+
CvSIGOP(ncv) = (UNOP_AUX*)CvSTART(ncv)->op_next;
2372823835
if (CvPADLIST(cv)) {
2372923836
PADNAMELIST *pnl = PadlistNAMES(CvPADLIST(cv));
2373023837
pnl = cv_clone_padname0(cv, pnl);

proto.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4185,6 +4185,13 @@ PERL_CALLCONV OP* Perl_op_clone_oplist(pTHX_ OP* o, OP* last, bool init)
41854185
#define PERL_ARGS_ASSERT_OP_CLONE_OPLIST \
41864186
assert(o)
41874187

4188+
PERL_CALLCONV OP* Perl_op_clone_optree(pTHX_ OP* o, bool init)
4189+
__attribute__global__
4190+
__attribute__warn_unused_result__
4191+
__attribute__nonnull__(pTHX_1);
4192+
#define PERL_ARGS_ASSERT_OP_CLONE_OPTREE \
4193+
assert(o)
4194+
41884195
PERL_CALLCONV OP* Perl_op_contextualize(pTHX_ OP* o, I32 context)
41894196
__attribute__global__
41904197
__attribute__nonnull__(pTHX_1);

0 commit comments

Comments
 (0)