diff options
Diffstat (limited to 'compile.c')
-rw-r--r-- | compile.c | 263 |
1 files changed, 139 insertions, 124 deletions
@@ -2709,7 +2709,7 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal optimize_checktype(iseq, iobj); if (IS_INSN_ID(iobj, jump)) { - INSN *niobj, *diobj, *piobj, *dniobj; + INSN *niobj, *diobj, *piobj; diobj = (INSN *)get_destination_insn(iobj); niobj = (INSN *)get_next_insn(iobj); @@ -2724,7 +2724,8 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal ELEM_REMOVE(&iobj->link); return COMPILE_OK; } - else if (iobj != diobj && IS_INSN_ID(diobj, jump) && + else if (iobj != diobj && IS_INSN(&diobj->link) && + IS_INSN_ID(diobj, jump) && OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0)) { /* * useless jump elimination: @@ -2740,12 +2741,7 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal remove_unreachable_chunk(iseq, iobj->link.next); goto again; } - else if (dniobj = 0, - IS_INSN_ID(diobj, leave) || - (diobj->operand_size == 0 && - (dniobj = (INSN *)get_next_insn(diobj)) != 0 && - (IS_INSN_ID(dniobj, leave) || (dniobj = 0)))) { - INSN *pop; + else if (IS_INSN_ID(diobj, leave)) { /* * jump LABEL * ... @@ -2753,29 +2749,19 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal * leave * => * leave - * pop * ... * LABEL: * leave */ /* replace */ unref_destination(iobj, 0); - iobj->insn_id = diobj->insn_id; + iobj->insn_id = BIN(leave); iobj->operand_size = 0; iobj->insn_info = diobj->insn_info; - if (dniobj) { - dniobj = new_insn_body(iseq, dniobj->insn_info.line_no, BIN(leave), 0); - ELEM_INSERT_NEXT(&iobj->link, &dniobj->link); - } - else { - dniobj = iobj; - } - /* adjust stack depth */ - pop = new_insn_body(iseq, diobj->insn_info.line_no, BIN(pop), 0); - ELEM_INSERT_NEXT(&dniobj->link, &pop->link); goto again; } - else if ((piobj = (INSN *)get_prev_insn(iobj)) != 0 && + else if (IS_INSN(iobj->link.prev) && + (piobj = (INSN *)iobj->link.prev) && (IS_INSN_ID(piobj, branchif) || IS_INSN_ID(piobj, branchunless))) { INSN *pdiobj = (INSN *)get_destination_insn(piobj); @@ -2877,109 +2863,135 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal * if L2 */ INSN *nobj = (INSN *)get_destination_insn(iobj); - INSN *pobj = (INSN *)iobj->link.prev; - int prev_dup = 0; - if (pobj) { - if (!IS_INSN(&pobj->link)) - pobj = 0; - else if (IS_INSN_ID(pobj, dup)) - prev_dup = 1; - } - - for (;;) { - if (IS_INSN_ID(nobj, jump)) { - replace_destination(iobj, nobj); - } - else if (prev_dup && IS_INSN_ID(nobj, dup) && - !!(nobj = (INSN *)nobj->link.next) && - /* basic blocks, with no labels in the middle */ - nobj->insn_id == iobj->insn_id) { - /* - * dup - * if L1 - * ... - * L1: - * dup - * if L2 - * => - * dup - * if L2 - * ... - * L1: - * dup - * if L2 - */ - replace_destination(iobj, nobj); - } - else if (pobj) { - /* - * putnil - * if L1 - * => - * # nothing - * - * putobject true - * if L1 - * => - * jump L1 - * - * putstring ".." - * if L1 - * => - * jump L1 - * - * putstring ".." - * dup - * if L1 - * => - * putstring ".." - * jump L1 - * - */ - int cond; - if (prev_dup && IS_INSN(pobj->link.prev)) { - pobj = (INSN *)pobj->link.prev; - } - if (IS_INSN_ID(pobj, putobject)) { - cond = (IS_INSN_ID(iobj, branchif) ? - OPERAND_AT(pobj, 0) != Qfalse : - IS_INSN_ID(iobj, branchunless) ? - OPERAND_AT(pobj, 0) == Qfalse : - FALSE); - } - else if (IS_INSN_ID(pobj, putstring) || - IS_INSN_ID(pobj, duparray) || - IS_INSN_ID(pobj, newarray)) { - cond = IS_INSN_ID(iobj, branchif); - } - else if (IS_INSN_ID(pobj, putnil)) { - cond = !IS_INSN_ID(iobj, branchif); - } - else break; - if (prev_dup || !IS_INSN_ID(pobj, newarray)) { - ELEM_REMOVE(iobj->link.prev); - } - else if (!iseq_pop_newarray(iseq, pobj)) { - pobj = new_insn_core(iseq, pobj->insn_info.line_no, BIN(pop), 0, NULL); - ELEM_INSERT_PREV(&iobj->link, &pobj->link); - } - if (cond) { - if (prev_dup) { - pobj = new_insn_core(iseq, pobj->insn_info.line_no, BIN(putnil), 0, NULL); - ELEM_INSERT_NEXT(&iobj->link, &pobj->link); - } - iobj->insn_id = BIN(jump); - goto again; - } - else { - unref_destination(iobj, 0); - ELEM_REMOVE(&iobj->link); - } - break; - } - else break; - nobj = (INSN *)get_destination_insn(nobj); - } + + /* This is super nasty hack!!! + * + * This jump-jump optimization may ignore event flags of the jump + * instruction being skipped. Actually, Line 2 TracePoint event + * is never fired in the following code: + * + * 1: raise if 1 == 2 + * 2: while true + * 3: break + * 4: end + * + * This is critical for coverage measurement. [Bug #15980] + * + * This is a stopgap measure: stop the jump-jump optimization if + * coverage measurement is enabled and if the skipped instruction + * has any event flag. + * + * Note that, still, TracePoint Line event does not occur on Line 2. + * This should be fixed in future. + */ + int stop_optimization = + ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq) && + nobj->insn_info.events; + if (!stop_optimization) { + INSN *pobj = (INSN *)iobj->link.prev; + int prev_dup = 0; + if (pobj) { + if (!IS_INSN(&pobj->link)) + pobj = 0; + else if (IS_INSN_ID(pobj, dup)) + prev_dup = 1; + } + + for (;;) { + if (IS_INSN(&nobj->link) && IS_INSN_ID(nobj, jump)) { + replace_destination(iobj, nobj); + } + else if (prev_dup && IS_INSN_ID(nobj, dup) && + !!(nobj = (INSN *)nobj->link.next) && + /* basic blocks, with no labels in the middle */ + nobj->insn_id == iobj->insn_id) { + /* + * dup + * if L1 + * ... + * L1: + * dup + * if L2 + * => + * dup + * if L2 + * ... + * L1: + * dup + * if L2 + */ + replace_destination(iobj, nobj); + } + else if (pobj) { + /* + * putnil + * if L1 + * => + * # nothing + * + * putobject true + * if L1 + * => + * jump L1 + * + * putstring ".." + * if L1 + * => + * jump L1 + * + * putstring ".." + * dup + * if L1 + * => + * putstring ".." + * jump L1 + * + */ + int cond; + if (prev_dup && IS_INSN(pobj->link.prev)) { + pobj = (INSN *)pobj->link.prev; + } + if (IS_INSN_ID(pobj, putobject)) { + cond = (IS_INSN_ID(iobj, branchif) ? + OPERAND_AT(pobj, 0) != Qfalse : + IS_INSN_ID(iobj, branchunless) ? + OPERAND_AT(pobj, 0) == Qfalse : + FALSE); + } + else if (IS_INSN_ID(pobj, putstring) || + IS_INSN_ID(pobj, duparray) || + IS_INSN_ID(pobj, newarray)) { + cond = IS_INSN_ID(iobj, branchif); + } + else if (IS_INSN_ID(pobj, putnil)) { + cond = !IS_INSN_ID(iobj, branchif); + } + else break; + if (prev_dup || !IS_INSN_ID(pobj, newarray)) { + ELEM_REMOVE(iobj->link.prev); + } + else if (!iseq_pop_newarray(iseq, pobj)) { + pobj = new_insn_core(iseq, pobj->insn_info.line_no, BIN(pop), 0, NULL); + ELEM_INSERT_PREV(&iobj->link, &pobj->link); + } + if (cond) { + if (prev_dup) { + pobj = new_insn_core(iseq, pobj->insn_info.line_no, BIN(putnil), 0, NULL); + ELEM_INSERT_NEXT(&iobj->link, &pobj->link); + } + iobj->insn_id = BIN(jump); + goto again; + } + else { + unref_destination(iobj, 0); + ELEM_REMOVE(&iobj->link); + } + break; + } + else break; + nobj = (INSN *)get_destination_insn(nobj); + } + } } if (IS_INSN_ID(iobj, pop)) { @@ -5042,6 +5054,9 @@ compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int branches); end_label = NEW_LABEL(line); ADD_INSNL(then_seq, line, jump, end_label); + if (!popped) { + ADD_INSN(then_seq, line, pop); + } } ADD_SEQ(ret, then_seq); } |