Permalink
Browse files

WIP TRY_OPLINES: Move cop_line from COP to every OP

This reduces the need for almost all nextstate ops (99%), which is an
overall win in memory and speed for typical undense code, say for
maybe less than 4 ops per line.
Error reporting and warnings is also correct for multiline ops
without a cop (such as conditionals).

TODO:
* add dbstate ops on debugging, instead of just converting the
  nextstate ops.
* Check if the first cop of a new file is set correctly.
* Use the new op_line in line reporting, and do only walk back to the prev. cop
  for the file name.
  • Loading branch information...
1 parent c63c00a commit cce87d19a584f1720eebef5636973f34f67d1c53 Reini Urban committed Sep 8, 2014
Showing with 64 additions and 2 deletions.
  1. +14 −0 cop.h
  2. +4 −0 ext/B/B.xs
  3. +27 −2 op.c
  4. +9 −0 op.h
  5. +10 −0 run.c
View
14 cop.h
@@ -370,11 +370,21 @@ string/length pair.
#include "mydtrace.h"
+/* TRY_OPLINES moves the cop_line to BASEOP.
+
+ Theory: On an average of 4 ops per line, and the reduced need for
+ runtime nextstates of 90% - only lexstate changes and file beginning
+ and the overhead of 5 ptrs per COP, we will win 4ptrs per reduced COP.
+ On typical 10k src with 40k ops it will be a 4 ptrs(5-1)*10k memory win: 40kb
+ (4 ops per line on average), plus the runtime win of ~about 4k ops, 8%. */
+
struct cop {
BASEOP
/* On LP64 putting this here takes advantage of the fact that BASEOP isn't
an exact multiple of 8 bytes to save structure padding. */
+#ifndef TRY_OPLINES
line_t cop_line; /* line # of this command */
+#endif
/* label for this construct is now stored in cop_hints_hash */
#ifdef USE_ITHREADS
PADOFFSET cop_stashoff; /* offset into PL_stashpad, for the
@@ -526,7 +536,11 @@ be zero.
#define CopLABEL_alloc(pv) ((pv)?savepv(pv):NULL)
#define CopSTASH_ne(c,hv) (!CopSTASH_eq(c,hv))
+#ifdef TRY_OPLINES
+#define CopLINE(c) ((c)->op_line)
+#else
#define CopLINE(c) ((c)->cop_line)
+#endif
#define CopLINE_inc(c) (++CopLINE(c))
#define CopLINE_dec(c) (--CopLINE(c))
#define CopLINE_set(c,l) (CopLINE(c) = (l))
View
@@ -682,7 +682,11 @@ struct OP_methods {
{ STR_WITH_LEN("gv"), SVp, STRUCT_OFFSET(struct svop, op_sv), },/*15*/
{ STR_WITH_LEN("padix"), PADOFFSETp,STRUCT_OFFSET(struct padop, op_padix),},/*16*/
{ STR_WITH_LEN("cop_seq"), U32p, STRUCT_OFFSET(struct cop, cop_seq), },/*17*/
+#ifdef TRY_OPLINES
+ { STR_WITH_LEN("line"), line_tp, STRUCT_OFFSET(struct cop, op_line), },/*18*/
+#else
{ STR_WITH_LEN("line"), line_tp, STRUCT_OFFSET(struct cop, cop_line), },/*18*/
+#endif
{ STR_WITH_LEN("hints"), U32p, STRUCT_OFFSET(struct cop, cop_hints), },/*19*/
#ifdef USE_ITHREADS
{ STR_WITH_LEN("pmoffset"),IVp, STRUCT_OFFSET(struct pmop, op_pmoffset),},/*20*/
View
29 op.c
@@ -109,6 +109,12 @@ recursive, but it's recursive on basic blocks, not on tree nodes.
#define CALL_RPEEP(o) PL_rpeepp(aTHX_ o)
#define CALL_OPFREEHOOK(o) if (PL_opfreehook) PL_opfreehook(aTHX_ o)
+#ifdef TRY_OPLINES
+# define STORE_COPLINE(op) CopLINE_set(op, PL_parser ? PL_parser->copline : PL_op->op_line);
+#else
+# define STORE_COPLINE(op)
+#endif
+
/* remove any leading "empty" ops from the op_next chain whose first
* node's address is stored in op_p. Store the updated address of the
* first node in op_p.
@@ -1354,15 +1360,20 @@ S_scalarboolean(pTHX_ OP *o)
if (o->op_type == OP_SASSIGN && cBINOPo->op_first->op_type == OP_CONST
&& !(cBINOPo->op_first->op_flags & OPf_SPECIAL)) {
if (ckWARN(WARN_SYNTAX)) {
- const line_t oldline = CopLINE(PL_curcop);
+#ifdef TRY_OPLINES
+ OP* op = PL_op ? PL_op : (OP*)PL_curcop;
+#else
+ OP* op = PL_curcop;
+#endif
+ const line_t oldline = CopLINE(op);
if (PL_parser && PL_parser->copline != NOLINE) {
/* This ensures that warnings are reported at the first line
of the conditional, not the last. */
CopLINE_set(PL_curcop, PL_parser->copline);
}
Perl_warner(aTHX_ packWARN(WARN_SYNTAX), "Found = in conditional, should be ==");
- CopLINE_set(PL_curcop, oldline);
+ CopLINE_set(op, oldline);
}
}
return scalar(o);
@@ -4159,6 +4170,7 @@ Perl_newLISTOP(pTHX_ I32 type, I32 flags, OP *first, OP *last)
listop->op_type = (OPCODE)type;
listop->op_ppaddr = PL_ppaddr[type];
+ STORE_COPLINE(listop);
if (first || last)
flags |= OPf_KIDS;
listop->op_flags = (U8)flags;
@@ -4230,6 +4242,7 @@ Perl_newOP(pTHX_ I32 type, I32 flags)
scalar(o);
if (PL_opargs[type] & OA_TARGET)
o->op_targ = pad_alloc(type, SVs_PADTMP);
+ STORE_COPLINE(o);
return CHECKOP(type, o);
}
@@ -4277,6 +4290,7 @@ Perl_newUNOP(pTHX_ I32 type, I32 flags, OP *first)
unop->op_first = first;
unop->op_flags = (U8)(flags | OPf_KIDS);
unop->op_private = (U8)(1 | (flags >> 8));
+ STORE_COPLINE(unop);
#ifdef PERL_OP_PARENT
if (!OP_HAS_SIBLING(first)) /* true unless weird syntax error */
@@ -4322,6 +4336,7 @@ Perl_newBINOP(pTHX_ I32 type, I32 flags, OP *first, OP *last)
binop->op_ppaddr = PL_ppaddr[type];
binop->op_first = first;
binop->op_flags = (U8)(flags | OPf_KIDS);
+ STORE_COPLINE(binop);
if (!last) {
last = first;
binop->op_private = (U8)(1 | (flags >> 8));
@@ -4717,6 +4732,7 @@ Perl_newPMOP(pTHX_ I32 type, I32 flags)
pmop->op_ppaddr = PL_ppaddr[type];
pmop->op_flags = (U8)flags;
pmop->op_private = (U8)(0 | (flags >> 8));
+ STORE_COPLINE(pmop);
if (PL_hints & HINT_RE_TAINT)
pmop->op_pmflags |= PMf_RETAINT;
@@ -5053,6 +5069,7 @@ Perl_pmruntime(pTHX_ OP *o, OP *expr, bool isreg, I32 floor)
rcop->op_flags |= ((PL_hints & HINT_RE_EVAL) ? OPf_SPECIAL : 0)
| (reglist ? OPf_STACKED : 0);
rcop->op_targ = cv_targ;
+ STORE_COPLINE(rcop);
/* /$x/ may cause an eval, since $x might be qr/(?{..})/ */
if (PL_hints & HINT_RE_EVAL) PL_cv_has_eval = 1;
@@ -5164,6 +5181,7 @@ Perl_newSVOP(pTHX_ I32 type, I32 flags, SV *sv)
scalar((OP*)svop);
if (PL_opargs[type] & OA_TARGET)
svop->op_targ = pad_alloc(type, SVs_PADTMP);
+ STORE_COPLINE(svop);
return CHECKOP(type, svop);
}
@@ -5209,6 +5227,7 @@ Perl_newPADOP(pTHX_ I32 type, I32 flags, SV *sv)
scalar((OP*)padop);
if (PL_opargs[type] & OA_TARGET)
padop->op_targ = pad_alloc(type, SVs_PADTMP);
+ STORE_COPLINE(padop);
return CHECKOP(type, padop);
}
@@ -5275,6 +5294,7 @@ Perl_newPVOP(pTHX_ I32 type, I32 flags, char *pv)
scalar((OP*)pvop);
if (PL_opargs[type] & OA_TARGET)
pvop->op_targ = pad_alloc(type, SVs_PADTMP);
+ STORE_COPLINE(pvop);
return CHECKOP(type, pvop);
}
@@ -8639,6 +8659,7 @@ Perl_ck_spair(pTHX_ OP *o)
newop = OP_SIBLING(kidkid);
if (newop) {
const OPCODE type = newop->op_type;
+ STORE_COPLINE(newop);
if (OP_HAS_SIBLING(newop) || !(PL_opargs[type] & OA_RETSCALAR) ||
type == OP_PADAV || type == OP_PADHV ||
type == OP_RV2AV || type == OP_RV2HV)
@@ -11251,7 +11272,11 @@ Perl_rpeep(pTHX_ OP *o)
/* Now steal all its pointers, and duplicate the other
data. */
+#ifdef TRY_OPLINES
+ firstcop->op_line = secondcop->op_line;
+#else
firstcop->cop_line = secondcop->cop_line;
+#endif
#ifdef USE_ITHREADS
firstcop->cop_stashoff = secondcop->cop_stashoff;
firstcop->cop_file = secondcop->cop_file;
View
9 op.h
@@ -26,6 +26,7 @@
* op_folded Result/remainder of a constant fold operation.
* op_lastsib this op is is the last sibling
* op_spare One spare bit
+ * op_line Current line number of this op (previously cop_line)
* op_flags Flags common to all operations. See OPf_* below.
* op_private Flags peculiar to a particular operation (BUT,
* by default, set to the number of children until
@@ -41,6 +42,13 @@ typedef PERL_BITFIELD16 Optype;
#ifdef BASEOP_DEFINITION
#define BASEOP BASEOP_DEFINITION
#else
+
+#ifdef TRY_OPLINES
+# define TRY_OPLINES_IN_BASEOP line_t op_line;
+#else
+# define TRY_OPLINES_IN_BASEOP
+#endif
+
#define BASEOP \
OP* op_next; \
OP* op_sibling; \
@@ -54,6 +62,7 @@ typedef PERL_BITFIELD16 Optype;
PERL_BITFIELD16 op_folded:1; \
PERL_BITFIELD16 op_lastsib:1; \
PERL_BITFIELD16 op_spare:1; \
+ TRY_OPLINES_IN_BASEOP \
U8 op_flags; \
U8 op_private;
#endif
View
10 run.c
@@ -40,6 +40,16 @@ Perl_runops_standard(pTHX)
OP_ENTRY_PROBE(OP_NAME(op));
while ((PL_op = op = op->op_ppaddr(aTHX))) {
OP_ENTRY_PROBE(OP_NAME(op));
+ /* Idea from Ben Morrow:
+ For each formerly nextstates clear the temp stack. So we put an op_line only
+ in the place of former nextstates */
+#ifdef TRY_OPLINES_NOT
+ if (PL_op->op_line) {
+ TAINT_NOT; /* Each statement is presumed innocent */
+ PL_stack_sp = PL_stack_base + cxstack[cxstack_ix].blk_oldsp;
+ FREETMPS;
+ }
+#endif
}
PERL_ASYNC_CHECK();

0 comments on commit cce87d1

Please sign in to comment.