From be3439026a6809f6f1f30bd063201bf472222fd0 Mon Sep 17 00:00:00 2001 From: mame Date: Wed, 20 Dec 2017 07:38:24 +0000 Subject: [PATCH] iseq.c (get_insn_info): use binary search instead of linear search This change introduces get_insn_info_binary_search, which is (should be) equivalent to the old get_insn_info. The old get_insn_info is renamed to get_insn_info_linear_search. When VM_CHECK_MODE > 0, the equivalence is validated at finish_iseq_build. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@61353 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- iseq.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 67 insertions(+), 6 deletions(-) diff --git a/iseq.c b/iseq.c index 186f8622e7..62e337f782 100644 --- a/iseq.c +++ b/iseq.c @@ -345,6 +345,10 @@ prepare_iseq_build(rb_iseq_t *iseq, return Qtrue; } +#if VM_CHECK_MODE > 0 +static void validate_get_insn_info(rb_iseq_t *iseq); +#endif + static VALUE finish_iseq_build(rb_iseq_t *iseq) { @@ -353,6 +357,10 @@ finish_iseq_build(rb_iseq_t *iseq) ISEQ_COMPILE_DATA_CLEAR(iseq); compile_data_free(data); +#if VM_CHECK_MODE > 0 + validate_get_insn_info(iseq); +#endif + if (RTEST(err)) { VALUE path = pathobj_path(iseq->body->location.pathobj); if (err == Qtrue) err = rb_exc_new_cstr(rb_eSyntaxError, "compile error"); @@ -1237,11 +1245,52 @@ iseqw_to_a(VALUE self) return iseq_data_to_ary(iseq); } -/* TODO: search algorithm is brute force. - this should be binary search or so. */ - static const struct iseq_insn_info_entry * -get_insn_info(const rb_iseq_t *iseq, size_t pos) +get_insn_info_binary_search(const rb_iseq_t *iseq, size_t pos) +{ + size_t size = iseq->body->insns_info_size; + const struct iseq_insn_info_entry *insns_info = iseq->body->insns_info; + const int debug = 0; + + if (debug) { + printf("size: %"PRIuSIZE"\n", size); + printf("insns_info[%"PRIuSIZE"]: position: %d, line: %d, pos: %"PRIuSIZE"\n", + (size_t)0, insns_info[0].position, insns_info[0].line_no, pos); + } + + if (size == 0) { + return NULL; + } + else if (size == 1) { + return &insns_info[0]; + } + else { + size_t l = 1, r = size - 1; + while (l <= r) { + size_t m = l + (r - l) / 2; + if (insns_info[m].position == pos) { + return &insns_info[m]; + } + if (insns_info[m].position < pos) { + l = m + 1; + } + else { + r = m - 1; + } + } + if (l >= size) { + return &insns_info[size-1]; + } + if (insns_info[l].position > pos) { + return &insns_info[l-1]; + } + return &insns_info[l]; + } +} + +#if VM_CHECK_MODE > 0 +static const struct iseq_insn_info_entry * +get_insn_info_linear_search(const rb_iseq_t *iseq, size_t pos) { size_t i = 0, size = iseq->body->insns_info_size; const struct iseq_insn_info_entry *insns_info = iseq->body->insns_info; @@ -1275,10 +1324,22 @@ get_insn_info(const rb_iseq_t *iseq, size_t pos) return &insns_info[i-1]; } +static void +validate_get_insn_info(rb_iseq_t *iseq) +{ + size_t i; + for (i = 0; i < iseq->body->iseq_size; i++) { + if (get_insn_info_linear_search(iseq, i) != get_insn_info_binary_search(iseq, i)) { + rb_bug("validate_get_insn_info: get_insn_info_linear_search(iseq, %"PRIuSIZE") != get_insn_info_binary_search(iseq, %"PRIuSIZE")", i, i); + } + } +} +#endif + unsigned int rb_iseq_line_no(const rb_iseq_t *iseq, size_t pos) { - const struct iseq_insn_info_entry *entry = get_insn_info(iseq, pos); + const struct iseq_insn_info_entry *entry = get_insn_info_binary_search(iseq, pos); if (entry) { return entry->line_no; @@ -1291,7 +1352,7 @@ rb_iseq_line_no(const rb_iseq_t *iseq, size_t pos) rb_event_flag_t rb_iseq_event_flags(const rb_iseq_t *iseq, size_t pos) { - const struct iseq_insn_info_entry *entry = get_insn_info(iseq, pos); + const struct iseq_insn_info_entry *entry = get_insn_info_binary_search(iseq, pos); if (entry) { return entry->events; }