From 47ea999b4689fc591478a05da1670d2008a4a705 Mon Sep 17 00:00:00 2001 From: mame Date: Sat, 20 Oct 2018 05:33:04 +0000 Subject: ext/coverage/: add the oneshot mode This patch introduces "oneshot_lines" mode for `Coverage.start`, which checks "whether each line was executed at least once or not", instead of "how many times each line was executed". A hook for each line is fired at most once, and after it is fired, the hook flag was removed; it runs with zero overhead. See [Feature #15022] in detail. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@65195 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- thread.c | 50 ++++++++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 22 deletions(-) (limited to 'thread.c') diff --git a/thread.c b/thread.c index b4baff6cba..443efb1e33 100644 --- a/thread.c +++ b/thread.c @@ -4323,11 +4323,16 @@ clear_coverage_i(st_data_t key, st_data_t val, st_data_t dummy) VALUE branches = RARRAY_AREF(coverage, COVERAGE_INDEX_BRANCHES); if (lines) { - for (i = 0; i < RARRAY_LEN(lines); i++) { - if (RARRAY_AREF(lines, i) != Qnil) { - RARRAY_ASET(lines, i, INT2FIX(0)); - } - } + if (GET_VM()->coverage_mode & COVERAGE_TARGET_ONESHOT_LINES) { + rb_ary_clear(lines); + } + else { + int i; + for (i = 0; i < RARRAY_LEN(lines); i++) { + if (RARRAY_AREF(lines, i) != Qnil) + RARRAY_ASET(lines, i, INT2FIX(0)); + } + } } if (branches) { VALUE counters = RARRAY_AREF(branches, 1); @@ -4339,8 +4344,8 @@ clear_coverage_i(st_data_t key, st_data_t val, st_data_t dummy) return ST_CONTINUE; } -static void -clear_coverage(void) +void +rb_clear_coverages(void) { VALUE coverages = rb_get_coverages(); if (RTEST(coverages)) { @@ -4373,7 +4378,7 @@ rb_thread_atfork_internal(rb_thread_t *th, void (*atfork)(rb_thread_t *, const r vm->fork_gen++; vm->sleeper = 0; - clear_coverage(); + rb_clear_coverages(); } static void @@ -5219,13 +5224,20 @@ rb_check_deadlock(rb_vm_t *vm) static void update_line_coverage(VALUE data, const rb_trace_arg_t *trace_arg) { - VALUE coverage = rb_iseq_coverage(GET_EC()->cfp->iseq); + const rb_control_frame_t *cfp = GET_EC()->cfp; + VALUE coverage = rb_iseq_coverage(cfp->iseq); if (RB_TYPE_P(coverage, T_ARRAY) && !RBASIC_CLASS(coverage)) { VALUE lines = RARRAY_AREF(coverage, COVERAGE_INDEX_LINES); if (lines) { long line = rb_sourceline() - 1; long count; VALUE num; + void rb_iseq_clear_event_flags(const rb_iseq_t *iseq, size_t pos, rb_event_flag_t reset); + if (GET_VM()->coverage_mode & COVERAGE_TARGET_ONESHOT_LINES) { + rb_iseq_clear_event_flags(cfp->iseq, cfp->pc - cfp->iseq->body->iseq_encoded - 1, RUBY_EVENT_COVERAGE_LINE); + rb_ary_push(lines, LONG2FIX(line + 1)); + return; + } if (line >= RARRAY_LEN(lines)) { /* no longer tracked */ return; } @@ -5340,6 +5352,12 @@ rb_get_coverages(void) return GET_VM()->coverages; } +int +rb_get_coverage_mode(void) +{ + return GET_VM()->coverage_mode; +} + void rb_set_coverages(VALUE coverages, int mode, VALUE me2counter) { @@ -5355,22 +5373,10 @@ rb_set_coverages(VALUE coverages, int mode, VALUE me2counter) } /* Make coverage arrays empty so old covered files are no longer tracked. */ -static int -reset_coverage_i(st_data_t key, st_data_t val, st_data_t dummy) -{ - VALUE coverage = (VALUE)val; - VALUE lines = RARRAY_AREF(coverage, COVERAGE_INDEX_LINES); - VALUE branches = RARRAY_AREF(coverage, COVERAGE_INDEX_BRANCHES); - if (lines) rb_ary_clear(lines); - if (branches) rb_ary_clear(branches); - return ST_CONTINUE; -} - void rb_reset_coverages(void) { - VALUE coverages = rb_get_coverages(); - st_foreach(rb_hash_tbl_raw(coverages), reset_coverage_i, 0); + rb_clear_coverages(); rb_iseq_remove_coverage_all(); GET_VM()->coverages = Qfalse; rb_remove_event_hook((rb_event_hook_func_t) update_line_coverage); -- cgit v1.2.3