mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Add #deconstruct cache to find pattern
This commit is contained in:
parent
5320375732
commit
c9ee34a18b
Notes:
git
2020-06-27 13:51:28 +09:00
2 changed files with 74 additions and 59 deletions
124
compile.c
124
compile.c
|
@ -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_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
|
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)
|
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);
|
ADD_INSNL(ret, line, branchunless, match_failed);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: this optimization allows us to re-use the #deconstruct value
|
CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, deconstructed_pos));
|
||||||
// (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);
|
|
||||||
ADD_INSN(ret, line, dup);
|
ADD_INSN(ret, line, dup);
|
||||||
ADD_SEND(ret, line, idLength, INT2FIX(0));
|
ADD_SEND(ret, line, idLength, INT2FIX(0));
|
||||||
ADD_INSN1(ret, line, putobject, INT2FIX(min_argc));
|
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 NODE *args = fpinfo->args;
|
||||||
const int args_num = fpinfo->args ? rb_long2int(fpinfo->args->nd_alen) : 0;
|
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);
|
match_failed = NEW_LABEL(line);
|
||||||
type_error = NEW_LABEL(line);
|
type_error = NEW_LABEL(line);
|
||||||
|
deconstruct = NEW_LABEL(line);
|
||||||
|
deconstructed = NEW_LABEL(line);
|
||||||
|
|
||||||
if (node->nd_pconst) {
|
if (node->nd_pconst) {
|
||||||
ADD_INSN(ret, line, dup);
|
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_INSNL(ret, line, branchunless, match_failed);
|
||||||
}
|
}
|
||||||
|
|
||||||
ADD_INSN(ret, line, dup);
|
CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, deconstructed_pos));
|
||||||
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);
|
|
||||||
|
|
||||||
ADD_INSN(ret, line, dup);
|
ADD_INSN(ret, line, dup);
|
||||||
ADD_SEND(ret, line, idLength, INT2FIX(0));
|
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));
|
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;
|
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, putobject, INT2FIX(0));
|
||||||
ADD_INSN1(ret, line, topn, INT2FIX(2));
|
ADD_INSN1(ret, line, topn, INT2FIX(2));
|
||||||
ADD_SEND(ret, line, idAREF, 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)) {
|
if (NODE_NAMED_REST_P(fpinfo->post_rest_arg)) {
|
||||||
ADD_INSN1(ret, line, topn, INT2FIX(3));
|
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_SEND(ret, line, idPLUS, INT2FIX(1));
|
||||||
ADD_INSN1(ret, line, topn, INT2FIX(3));
|
ADD_INSN1(ret, line, topn, INT2FIX(3));
|
||||||
ADD_SEND(ret, line, idAREF, INT2FIX(2));
|
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);
|
ADD_INSNL(ret, line, jump, find_succeeded);
|
||||||
|
|
||||||
|
@ -6288,6 +6239,61 @@ iseq_compile_pattern_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *
|
||||||
return COMPILE_OK;
|
return COMPILE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
static int
|
||||||
compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
|
compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1340,6 +1340,15 @@ END
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
assert_block do
|
||||||
|
case CDeconstructCache.new([[0, :a, 1]])
|
||||||
|
in [*, String => x, *]
|
||||||
|
false
|
||||||
|
in [*, Symbol => x, *]
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
################################################################
|
################################################################
|
||||||
|
|
Loading…
Reference in a new issue