Skip to content

Commit 125cf57

Browse files
committed
[MERGE] add OP_MULTICONCAT and optimize_optree()
This branch contains one main commit which adds the new OP_MULTICONCAT op, plus a few prior commits to provide support; in particular, adding an extra top-down optree scan phase to allow extra optimisation opportunities, just before the peephole optimiser is run. See the OP_MULTICONCAT for more details, but in summary it: allows multiple OP_CONCAT, OP_CONST ops, plus optionally an OP_SASSIGN or OP_STRINGIFY, to be combined into a single OP_MULTICONCAT op, which can make things a *lot* faster: 4x or more.
2 parents ab340ff + 8ed1839 commit 125cf57

31 files changed

+4480
-648
lines changed

dist/Safe/t/safeops.t

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ exists exists $h{Key}
234234
rv2hv %h
235235
helem $h{kEy}
236236
hslice @h{kEy}
237+
multiconcat SKIP (set by optimizer)
237238
multideref SKIP (set by optimizer)
238239
unpack unpack
239240
pack pack

dump.c

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1141,6 +1141,15 @@ S_do_op_dump_bar(pTHX_ I32 level, UV bar, PerlIO *file, const OP *o)
11411141
break;
11421142
}
11431143

1144+
case OP_MULTICONCAT:
1145+
S_opdump_indent(aTHX_ o, level, bar, file, "NARGS = %" UVuf "\n",
1146+
cUNOP_AUXo->op_aux[PERL_MULTICONCAT_IX_NARGS].uv);
1147+
/* XXX really ought to dump each field individually,
1148+
* but that's too much like hard work */
1149+
S_opdump_indent(aTHX_ o, level, bar, file, "CONSTS = (%" SVf ")\n",
1150+
SVfARG(multiconcat_stringify(o)));
1151+
break;
1152+
11441153
case OP_CONST:
11451154
case OP_HINTSEVAL:
11461155
case OP_METHOD_NAMED:
@@ -2728,6 +2737,48 @@ Perl_multideref_stringify(pTHX_ const OP *o, CV *cv)
27282737
}
27292738

27302739

2740+
/* Return a temporary SV containing a stringified representation of
2741+
* the op_aux field of a MULTICONCAT op. Note that if the aux contains
2742+
* both plain and utf8 versions of the const string and indices, only
2743+
* the first is displayed.
2744+
*/
2745+
2746+
SV*
2747+
Perl_multiconcat_stringify(pTHX_ const OP *o)
2748+
{
2749+
UNOP_AUX_item *aux = cUNOP_AUXo->op_aux;
2750+
UNOP_AUX_item *lens;
2751+
STRLEN len;
2752+
UV nargs;
2753+
char *s;
2754+
SV *out = newSVpvn_flags("", 0, SVs_TEMP);
2755+
2756+
PERL_ARGS_ASSERT_MULTICONCAT_STRINGIFY;
2757+
2758+
nargs = aux[PERL_MULTICONCAT_IX_NARGS].uv;
2759+
s = aux[PERL_MULTICONCAT_IX_PLAIN_PV].pv;
2760+
len = aux[PERL_MULTICONCAT_IX_PLAIN_LEN].size;
2761+
if (!s) {
2762+
s = aux[PERL_MULTICONCAT_IX_UTF8_PV].pv;
2763+
len = aux[PERL_MULTICONCAT_IX_UTF8_LEN].size;
2764+
sv_catpvs(out, "UTF8 ");
2765+
}
2766+
pv_pretty(out, s, len, 50,
2767+
NULL, NULL,
2768+
(PERL_PV_PRETTY_NOCLEAR
2769+
|PERL_PV_PRETTY_QUOTE
2770+
|PERL_PV_PRETTY_ELLIPSES));
2771+
2772+
lens = aux + PERL_MULTICONCAT_IX_LENGTHS;
2773+
nargs++;
2774+
while (nargs-- > 0) {
2775+
Perl_sv_catpvf(aTHX_ out, ",%" IVdf, (IV)lens->size);
2776+
lens++;
2777+
}
2778+
return out;
2779+
}
2780+
2781+
27312782
I32
27322783
Perl_debop(pTHX_ const OP *o)
27332784
{
@@ -2772,6 +2823,11 @@ Perl_debop(pTHX_ const OP *o)
27722823
SVfARG(multideref_stringify(o, deb_curcv(cxstack_ix))));
27732824
break;
27742825

2826+
case OP_MULTICONCAT:
2827+
PerlIO_printf(Perl_debug_log, "(%" SVf ")",
2828+
SVfARG(multiconcat_stringify(o)));
2829+
break;
2830+
27752831
default:
27762832
break;
27772833
}

embed.fnc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,7 @@ Afp |void |deb |NN const char* pat|...
395395
Ap |void |vdeb |NN const char* pat|NULLOK va_list* args
396396
Ap |void |debprofdump
397397
EXp |SV* |multideref_stringify |NN const OP* o|NULLOK CV *cv
398+
EXp |SV* |multiconcat_stringify |NN const OP* o
398399
Ap |I32 |debop |NN const OP* o
399400
Ap |I32 |debstack
400401
Ap |I32 |debstackptrs
@@ -1046,7 +1047,9 @@ Apn |void |mini_mktime |NN struct tm *ptm
10461047
AMmd |OP* |op_lvalue |NULLOK OP* o|I32 type
10471048
poX |OP* |op_lvalue_flags|NULLOK OP* o|I32 type|U32 flags
10481049
p |void |finalize_optree |NN OP* o
1050+
p |void |optimize_optree|NN OP* o
10491051
#if defined(PERL_IN_OP_C)
1052+
s |void |optimize_op |NN OP* o
10501053
s |void |finalize_op |NN OP* o
10511054
s |void |move_proto_attr|NN OP **proto|NN OP **attrs \
10521055
|NN const GV *name|bool curstash

embed.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -923,6 +923,7 @@
923923
#define cv_ckproto_len_flags(a,b,c,d,e) Perl_cv_ckproto_len_flags(aTHX_ a,b,c,d,e)
924924
#define grok_atoUV Perl_grok_atoUV
925925
#define mg_find_mglob(a) Perl_mg_find_mglob(aTHX_ a)
926+
#define multiconcat_stringify(a) Perl_multiconcat_stringify(aTHX_ a)
926927
#define multideref_stringify(a,b) Perl_multideref_stringify(aTHX_ a,b)
927928
#define op_clear(a) Perl_op_clear(aTHX_ a)
928929
#define qerror(a) Perl_qerror(aTHX_ a)
@@ -1337,6 +1338,7 @@
13371338
#define oopsAV(a) Perl_oopsAV(aTHX_ a)
13381339
#define oopsHV(a) Perl_oopsHV(aTHX_ a)
13391340
#define op_unscope(a) Perl_op_unscope(aTHX_ a)
1341+
#define optimize_optree(a) Perl_optimize_optree(aTHX_ a)
13401342
#define package(a) Perl_package(aTHX_ a)
13411343
#define package_version(a) Perl_package_version(aTHX_ a)
13421344
#define pad_add_weakref(a) Perl_pad_add_weakref(aTHX_ a)
@@ -1647,6 +1649,7 @@
16471649
#define no_fh_allowed(a) S_no_fh_allowed(aTHX_ a)
16481650
#define op_integerize(a) S_op_integerize(aTHX_ a)
16491651
#define op_std_init(a) S_op_std_init(aTHX_ a)
1652+
#define optimize_op(a) S_optimize_op(aTHX_ a)
16501653
#define pmtrans(a,b,c) S_pmtrans(aTHX_ a,b,c)
16511654
#define process_special_blocks(a,b,c,d) S_process_special_blocks(aTHX_ a,b,c,d)
16521655
#define ref_array_or_hash(a) S_ref_array_or_hash(aTHX_ a)

ext/B/B.xs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1183,6 +1183,10 @@ string(o, cv)
11831183
PPCODE:
11841184
aux = cUNOP_AUXo->op_aux;
11851185
switch (o->op_type) {
1186+
case OP_MULTICONCAT:
1187+
ret = multiconcat_stringify(o);
1188+
break;
1189+
11861190
case OP_MULTIDEREF:
11871191
ret = multideref_stringify(o, cv);
11881192
break;
@@ -1238,6 +1242,61 @@ aux_list(o, cv)
12381242
(char)aux[2].iv) : &PL_sv_no));
12391243
break;
12401244

1245+
case OP_MULTICONCAT:
1246+
{
1247+
UV nargs = aux[0].uv;
1248+
char *p;
1249+
STRLEN len;
1250+
U32 utf8 = 0;
1251+
SV *sv;
1252+
UNOP_AUX_item *lens;
1253+
1254+
/* return (nargs, const string, segment len 0, 1, 2, ...) */
1255+
1256+
/* if this changes, this block of code probably needs fixing */
1257+
assert(PERL_MULTICONCAT_HEADER_SIZE == 5);
1258+
nargs = aux[PERL_MULTICONCAT_IX_NARGS].uv;
1259+
EXTEND(SP, ((SSize_t)(2 + (nargs+1))));
1260+
PUSHs(sv_2mortal(newSViv(nargs)));
1261+
1262+
p = aux[PERL_MULTICONCAT_IX_PLAIN_PV].pv;
1263+
len = aux[PERL_MULTICONCAT_IX_PLAIN_LEN].size;
1264+
if (!p) {
1265+
p = aux[PERL_MULTICONCAT_IX_UTF8_PV].pv;
1266+
len = aux[PERL_MULTICONCAT_IX_UTF8_LEN].size;
1267+
utf8 = SVf_UTF8;
1268+
}
1269+
sv = newSVpvn(p, len);
1270+
SvFLAGS(sv) |= utf8;
1271+
PUSHs(sv_2mortal(sv));
1272+
1273+
lens = aux + PERL_MULTICONCAT_IX_LENGTHS;
1274+
nargs++; /* loop (nargs+1) times */
1275+
if (utf8) {
1276+
U8 *p = (U8*)SvPVX(sv);
1277+
while (nargs--) {
1278+
SSize_t bytes = lens->size;
1279+
SSize_t chars;
1280+
if (bytes <= 0)
1281+
chars = bytes;
1282+
else {
1283+
/* return char lengths rather than byte lengths */
1284+
chars = utf8_length(p, p + bytes);
1285+
p += bytes;
1286+
}
1287+
lens++;
1288+
PUSHs(sv_2mortal(newSViv(chars)));
1289+
}
1290+
}
1291+
else {
1292+
while (nargs--) {
1293+
PUSHs(sv_2mortal(newSViv(lens->size)));
1294+
lens++;
1295+
}
1296+
}
1297+
break;
1298+
}
1299+
12411300
case OP_MULTIDEREF:
12421301
#ifdef USE_ITHREADS
12431302
# define ITEM_SV(item) *av_fetch(comppad, (item)->pad_offset, FALSE);

0 commit comments

Comments
 (0)