Skip to content

Instantly share code, notes, and snippets.

@wanabe
Created July 24, 2021 09:52
Show Gist options
  • Save wanabe/2c7c0606f3bd45e06adbe87bd31f311b to your computer and use it in GitHub Desktop.
Save wanabe/2c7c0606f3bd45e06adbe87bd31f311b to your computer and use it in GitHub Desktop.
diff --git a/compile.c b/compile.c
index 1cabb8cccd..9e3a1111dc 100644
--- a/compile.c
+++ b/compile.c
@@ -6562,7 +6562,7 @@ iseq_compile_array_deconstruct(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NO
ADD_INSNL(ret, line, branchunless, match_failed);
- ADD_SEND(ret, line, rb_intern("deconstruct"), INT2FIX(0));
+ ADD_INSN(ret, line, deconstruct);
// Cache the result (if it's cacheable - currently, only top-level array patterns)
if (deconstructed_pos) {
diff --git a/defs/id.def b/defs/id.def
index fc7a04ffbc..41cc51adb7 100644
--- a/defs/id.def
+++ b/defs/id.def
@@ -56,6 +56,7 @@ firstline, predefined = __LINE__+1, %[\
quo
name
nil
+ deconstruct
_ UScore
diff --git a/insns.def b/insns.def
index 8d609927b5..e42048dd2a 100644
--- a/insns.def
+++ b/insns.def
@@ -1422,6 +1422,16 @@ opt_regexpmatch2
}
}
+/* deconstruct */
+DEFINE_INSN
+deconstruct
+()
+(VALUE recv)
+(VALUE val)
+{
+ val = vm_deconstruct(recv);
+}
+
/* call native compiled method */
DEFINE_INSN_IF(SUPPORT_CALL_C_FUNCTION)
opt_call_c_function
diff --git a/vm.c b/vm.c
index 8c62d7dd91..5a7144ee69 100644
--- a/vm.c
+++ b/vm.c
@@ -1927,6 +1927,7 @@ vm_init_redefined_flag(void)
OP(And, AND), (C(Integer));
OP(Or, OR), (C(Integer));
OP(NilP, NIL_P), (C(NilClass));
+ OP(Deconstruct, DECONSTRUCT), (C(Array));
#undef C
#undef OP
}
diff --git a/vm_core.h b/vm_core.h
index f21d85032c..c051fa7e5c 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -538,6 +538,7 @@ enum ruby_basic_operators {
BOP_CALL,
BOP_AND,
BOP_OR,
+ BOP_DECONSTRUCT,
BOP_LAST_
};
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index 840bd490b6..08000bf7ff 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -5250,6 +5250,14 @@ vm_opt_regexpmatch2(VALUE recv, VALUE obj)
}
}
+static VALUE
+vm_deconstruct(VALUE recv) {
+ if (RBASIC_CLASS(recv) == rb_cArray && BASIC_OP_UNREDEFINED_P(BOP_DECONSTRUCT, ARRAY_REDEFINED_OP_FLAG)) {
+ return recv;
+ }
+ return rb_funcall(recv, rb_intern("deconstruct"), 0);
+}
+
rb_event_flag_t rb_iseq_event_flags(const rb_iseq_t *iseq, size_t pos);
NOINLINE(static void vm_trace(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp));
diff --git a/compile.c b/compile.c
index 1cabb8cccd..38bc3fb2a9 100644
--- a/compile.c
+++ b/compile.c
@@ -6304,14 +6304,10 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
ADD_SEND(ret, line, idRespond_to, INT2FIX(1));
ADD_INSNL(ret, line, branchunless, match_failed);
- if (NIL_P(keys)) {
- ADD_INSN(ret, line, putnil);
- }
- else {
- ADD_INSN1(ret, line, duparray, keys);
+ if (!NIL_P(keys)) {
RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys));
}
- ADD_SEND(ret, line, rb_intern("deconstruct_keys"), INT2FIX(1));
+ ADD_INSN1(ret, line, deconstruct_keys, keys);
ADD_INSN(ret, line, dup);
ADD_INSN1(ret, line, checktype, INT2FIX(T_HASH));
diff --git a/defs/id.def b/defs/id.def
index fc7a04ffbc..83fd2f316e 100644
--- a/defs/id.def
+++ b/defs/id.def
@@ -56,6 +56,7 @@ firstline, predefined = __LINE__+1, %[\
quo
name
nil
+ deconstruct_keys
_ UScore
diff --git a/insns.def b/insns.def
index 8d609927b5..ab4d5aeb98 100644
--- a/insns.def
+++ b/insns.def
@@ -1422,6 +1422,16 @@ opt_regexpmatch2
}
}
+/* deconstruct_keys */
+DEFINE_INSN
+deconstruct_keys
+(VALUE keys)
+(VALUE recv)
+(VALUE val)
+{
+ val = vm_deconstruct_keys(recv, keys);
+}
+
/* call native compiled method */
DEFINE_INSN_IF(SUPPORT_CALL_C_FUNCTION)
opt_call_c_function
diff --git a/vm.c b/vm.c
index 8c62d7dd91..517b4e55ef 100644
--- a/vm.c
+++ b/vm.c
@@ -1927,6 +1927,7 @@ vm_init_redefined_flag(void)
OP(And, AND), (C(Integer));
OP(Or, OR), (C(Integer));
OP(NilP, NIL_P), (C(NilClass));
+ OP(Deconstruct_keys, DECONSTRUCT_KEYS), (C(Hash));
#undef C
#undef OP
}
diff --git a/vm_core.h b/vm_core.h
index f21d85032c..471d6581ed 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -538,6 +538,7 @@ enum ruby_basic_operators {
BOP_CALL,
BOP_AND,
BOP_OR,
+ BOP_DECONSTRUCT_KEYS,
BOP_LAST_
};
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index 840bd490b6..d24386dd27 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -5250,6 +5250,17 @@ vm_opt_regexpmatch2(VALUE recv, VALUE obj)
}
}
+static VALUE
+vm_deconstruct_keys(VALUE recv, VALUE keys) {
+ if (RBASIC_CLASS(recv) == rb_cHash && BASIC_OP_UNREDEFINED_P(BOP_DECONSTRUCT_KEYS, HASH_REDEFINED_OP_FLAG)) {
+ return recv;
+ }
+ if (RB_BUILTIN_TYPE(keys) == T_ARRAY) {
+ keys = rb_ary_resurrect(keys);
+ }
+ return rb_funcallv(recv, rb_intern("deconstruct_keys"), 1, &keys);
+}
+
rb_event_flag_t rb_iseq_event_flags(const rb_iseq_t *iseq, size_t pos);
NOINLINE(static void vm_trace(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment