diff options
author | Vladimir Dementyev <dementiev.vm@gmail.com> | 2020-06-14 22:00:51 +0300 |
---|---|---|
committer | Kazuki Tsujimoto <kazuki@callcc.net> | 2020-06-27 13:51:03 +0900 |
commit | c9ee34a18bb833b11ce64f6d35fa0e7f1a865a14 (patch) | |
tree | af0e6b55659d15008a799687196b05da15eb1e58 /compile.c | |
parent | 5320375732a400ef915c8acbf810aed4ac5261b7 (diff) | |
download | ruby-c9ee34a18bb833b11ce64f6d35fa0e7f1a865a14.tar.gz |
Add #deconstruct cache to find pattern
Diffstat (limited to 'compile.c')
-rw-r--r-- | compile.c | 124 |
1 files changed, 65 insertions, 59 deletions
@@ -5611,6 +5611,8 @@ compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_no static int iseq_compile_pattern_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *unmatched, int in_alt_pattern, int deconstructed_pos); +static int iseq_compile_array_deconstruct(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *deconstruct, LABEL *deconstructed, LABEL *match_failed, LABEL *type_error, int deconstructed_pos); + static int iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *matched, LABEL *unmatched, int in_alt_pattern, int deconstructed_pos) { @@ -5701,52 +5703,8 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c ADD_INSNL(ret, line, branchunless, match_failed); } - // NOTE: this optimization allows us to re-use the #deconstruct value - // (or its absence). - // `deconstructed_pos` contains the distance to the stack relative location - // where the value is stored. - if (deconstructed_pos) { - // If value is nil then we haven't tried to deconstruct - ADD_INSN1(ret, line, topn, INT2FIX(deconstructed_pos)); - ADD_INSNL(ret, line, branchnil, deconstruct); - - // If false then the value is not deconstructable - ADD_INSN1(ret, line, topn, INT2FIX(deconstructed_pos)); - ADD_INSNL(ret, line, branchunless, match_failed); + CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, deconstructed_pos)); - // Drop value, add deconstructed to the stack and jump - ADD_INSN(ret, line, pop); - ADD_INSN1(ret, line, topn, INT2FIX(deconstructed_pos - 1)); - ADD_INSNL(ret, line, jump, deconstructed); - } else { - ADD_INSNL(ret, line, jump, deconstruct); - } - - ADD_LABEL(ret, deconstruct); - ADD_INSN(ret, line, dup); - ADD_INSN1(ret, line, putobject, ID2SYM(rb_intern("deconstruct"))); - ADD_SEND(ret, line, idRespond_to, INT2FIX(1)); - - // Cache the result of respond_to? (in case it's false is stays there, if true — it's overwritten after #deconstruct) - if (deconstructed_pos) { - ADD_INSN1(ret, line, setn, INT2FIX(deconstructed_pos + 1)); - } - - ADD_INSNL(ret, line, branchunless, match_failed); - - ADD_SEND(ret, line, rb_intern("deconstruct"), INT2FIX(0)); - - // Cache the result (if it's cacheable — currently, only top-level array patterns) - if (deconstructed_pos) { - ADD_INSN1(ret, line, setn, INT2FIX(deconstructed_pos)); - } - - ADD_INSN(ret, line, dup); - ADD_INSN1(ret, line, checktype, INT2FIX(T_ARRAY)); - ADD_INSNL(ret, line, branchunless, type_error); - ADD_INSNL(ret, line, jump, deconstructed); - - ADD_LABEL(ret, deconstructed); ADD_INSN(ret, line, dup); ADD_SEND(ret, line, idLength, INT2FIX(0)); ADD_INSN1(ret, line, putobject, INT2FIX(min_argc)); @@ -5873,9 +5831,11 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c const NODE *args = fpinfo->args; const int args_num = fpinfo->args ? rb_long2int(fpinfo->args->nd_alen) : 0; - LABEL *match_failed, *type_error; + LABEL *match_failed, *type_error, *deconstruct, *deconstructed; match_failed = NEW_LABEL(line); type_error = NEW_LABEL(line); + deconstruct = NEW_LABEL(line); + deconstructed = NEW_LABEL(line); if (node->nd_pconst) { ADD_INSN(ret, line, dup); @@ -5884,16 +5844,7 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c ADD_INSNL(ret, line, branchunless, match_failed); } - ADD_INSN(ret, line, dup); - ADD_INSN1(ret, line, putobject, ID2SYM(rb_intern("deconstruct"))); - ADD_SEND(ret, line, idRespond_to, INT2FIX(1)); - ADD_INSNL(ret, line, branchunless, match_failed); - - ADD_SEND(ret, line, rb_intern("deconstruct"), INT2FIX(0)); - - ADD_INSN(ret, line, dup); - ADD_INSN1(ret, line, checktype, INT2FIX(T_ARRAY)); - ADD_INSNL(ret, line, branchunless, type_error); + CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, deconstructed_pos)); ADD_INSN(ret, line, dup); ADD_SEND(ret, line, idLength, INT2FIX(0)); @@ -5933,7 +5884,7 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c } ADD_SEND(ret, line, idAREF, INT2FIX(1)); - CHECK(iseq_compile_pattern_match(iseq, ret, args->nd_head, next_loop, in_alt_pattern)); + CHECK(iseq_compile_pattern_match(iseq, ret, args->nd_head, next_loop, in_alt_pattern, FALSE)); args = args->nd_next; } @@ -5942,7 +5893,7 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c ADD_INSN1(ret, line, putobject, INT2FIX(0)); ADD_INSN1(ret, line, topn, INT2FIX(2)); ADD_SEND(ret, line, idAREF, INT2FIX(2)); - CHECK(iseq_compile_pattern_match(iseq, ret, fpinfo->pre_rest_arg, find_failed, in_alt_pattern)); + CHECK(iseq_compile_pattern_match(iseq, ret, fpinfo->pre_rest_arg, find_failed, in_alt_pattern, FALSE)); } if (NODE_NAMED_REST_P(fpinfo->post_rest_arg)) { ADD_INSN1(ret, line, topn, INT2FIX(3)); @@ -5951,7 +5902,7 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c ADD_SEND(ret, line, idPLUS, INT2FIX(1)); ADD_INSN1(ret, line, topn, INT2FIX(3)); ADD_SEND(ret, line, idAREF, INT2FIX(2)); - CHECK(iseq_compile_pattern_match(iseq, ret, fpinfo->post_rest_arg, find_failed, in_alt_pattern)); + CHECK(iseq_compile_pattern_match(iseq, ret, fpinfo->post_rest_arg, find_failed, in_alt_pattern, FALSE)); } ADD_INSNL(ret, line, jump, find_succeeded); @@ -6289,6 +6240,61 @@ iseq_compile_pattern_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE * } static int +iseq_compile_array_deconstruct(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *deconstruct, LABEL *deconstructed, LABEL *match_failed, LABEL *type_error, int deconstructed_pos) +{ + const int line = nd_line(node); + + // NOTE: this optimization allows us to re-use the #deconstruct value + // (or its absence). + // `deconstructed_pos` contains the distance to the stack relative location + // where the value is stored. + if (deconstructed_pos) { + // If value is nil then we haven't tried to deconstruct + ADD_INSN1(ret, line, topn, INT2FIX(deconstructed_pos)); + ADD_INSNL(ret, line, branchnil, deconstruct); + + // If false then the value is not deconstructable + ADD_INSN1(ret, line, topn, INT2FIX(deconstructed_pos)); + ADD_INSNL(ret, line, branchunless, match_failed); + + // Drop value, add deconstructed to the stack and jump + ADD_INSN(ret, line, pop); + ADD_INSN1(ret, line, topn, INT2FIX(deconstructed_pos - 1)); + ADD_INSNL(ret, line, jump, deconstructed); + } else { + ADD_INSNL(ret, line, jump, deconstruct); + } + + ADD_LABEL(ret, deconstruct); + ADD_INSN(ret, line, dup); + ADD_INSN1(ret, line, putobject, ID2SYM(rb_intern("deconstruct"))); + ADD_SEND(ret, line, idRespond_to, INT2FIX(1)); + + // Cache the result of respond_to? (in case it's false is stays there, if true — it's overwritten after #deconstruct) + if (deconstructed_pos) { + ADD_INSN1(ret, line, setn, INT2FIX(deconstructed_pos + 1)); + } + + ADD_INSNL(ret, line, branchunless, match_failed); + + ADD_SEND(ret, line, rb_intern("deconstruct"), INT2FIX(0)); + + // Cache the result (if it's cacheable — currently, only top-level array patterns) + if (deconstructed_pos) { + ADD_INSN1(ret, line, setn, INT2FIX(deconstructed_pos)); + } + + ADD_INSN(ret, line, dup); + ADD_INSN1(ret, line, checktype, INT2FIX(T_ARRAY)); + ADD_INSNL(ret, line, branchunless, type_error); + ADD_INSNL(ret, line, jump, deconstructed); + + ADD_LABEL(ret, deconstructed); + + return COMPILE_OK; +} + +static int compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped) { const NODE *pattern; |