summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authork0kubun <k0kubun@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-03-04 07:04:28 +0000
committerk0kubun <k0kubun@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-03-04 07:04:28 +0000
commit33949a03203c7d0235ec1823b3827618237057a1 (patch)
treec79d8cfb6f12c59243a4e1bc03dfbf0e15ab0594
parentae34216021b1f627f99f8845c8376ad54ccdfa08 (diff)
compile.c: set catch_except_p flag
to be used for MJIT's optimization. It's not used for optimization in this commit yet. vm_core.h: added catch_except_p field. iseq.c: show the flag in ISeq disasm for debugging. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62654 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--compile.c49
-rw-r--r--iseq.c1
-rw-r--r--vm_core.h1
3 files changed, 51 insertions, 0 deletions
diff --git a/compile.c b/compile.c
index 4876a06..818eb96 100644
--- a/compile.c
+++ b/compile.c
@@ -1254,6 +1254,53 @@ new_child_iseq_ifunc(rb_iseq_t *iseq, const struct vm_ifunc *ifunc,
return ret_iseq;
}
+/* Set body->catch_except_p to TRUE if the ISeq may catch an exception. If it is FALSE,
+ JIT-ed code may be optimized. If we are extremely conservative, we should set TRUE
+ if catch table exists. But we want to optimize while loop, which always has catch
+ table entries for break/next/redo.
+
+ So this function sets TRUE for limited ISeqs with break/next/redo catch table entries
+ whose child ISeq would really raise an exception. */
+static void
+update_catch_except_flags(struct rb_iseq_constant_body *body)
+{
+ unsigned int pos;
+ size_t i;
+ int insn;
+ const struct iseq_catch_table *ct = body->catch_table;
+
+ /* This assumes that a block has parent_iseq which may catch an exception from the block, and that
+ BREAK/NEXT/REDO catch table entries are used only when `throw` insn is used in the block. */
+ if (body->parent_iseq != NULL) {
+ pos = 0;
+ while (pos < body->iseq_size) {
+#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
+ insn = rb_vm_insn_addr2insn((void *)body->iseq_encoded[pos]);
+#else
+ insn = (int)body->iseq_encoded[pos];
+#endif
+ if (insn == BIN(throw)) {
+ struct rb_iseq_constant_body *parent_body = body->parent_iseq->body;
+ parent_body->catch_except_p = TRUE;
+ }
+ pos += insn_len(insn);
+ }
+ }
+
+ if (ct == NULL)
+ return;
+
+ for (i = 0; i < ct->size; i++) {
+ const struct iseq_catch_table_entry *entry = &ct->entries[i];
+ if (entry->type != CATCH_TYPE_BREAK
+ && entry->type != CATCH_TYPE_NEXT
+ && entry->type != CATCH_TYPE_REDO) {
+ body->catch_except_p = TRUE;
+ break;
+ }
+ }
+}
+
static int
iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
{
@@ -1299,6 +1346,8 @@ iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
debugs("[compile step 5 (iseq_translate_threaded_code)] \n");
if (!rb_iseq_translate_threaded_code(iseq)) return COMPILE_NG;
+ update_catch_except_flags(iseq->body);
+
if (compile_debug > 1) {
VALUE str = rb_iseq_disasm(iseq);
printf("%s\n", StringValueCStr(str));
diff --git a/iseq.c b/iseq.c
index b703baa..27bf45f 100644
--- a/iseq.c
+++ b/iseq.c
@@ -1809,6 +1809,7 @@ rb_iseq_disasm(const rb_iseq_t *iseq)
rb_str_cat2(str, "== disasm: ");
rb_str_concat(str, iseq_inspect(iseq));
+ rb_str_catf(str, " (catch: %s)", iseq->body->catch_except_p ? "TRUE" : "FALSE");
if ((l = RSTRING_LEN(str)) < header_minlen) {
rb_str_resize(str, header_minlen);
memset(RSTRING_PTR(str) + l, '=', header_minlen - l);
diff --git a/vm_core.h b/vm_core.h
index 0a62b66..4e7eaed 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -424,6 +424,7 @@ struct rb_iseq_constant_body {
struct rb_control_frame_struct *); /* function pointer for loaded native code */
long unsigned total_calls; /* number of total calls with `mjit_exec()` */
struct rb_mjit_unit *jit_unit;
+ char catch_except_p; /* If a frame of this ISeq may catch exception, set TRUE */
};
/* T_IMEMO/iseq */