aboutsummaryrefslogtreecommitdiffstats
path: root/compile.c
diff options
context:
space:
mode:
authorKoichi Sasada <ko1@atdot.net>2019-11-15 17:49:49 +0900
committerKoichi Sasada <ko1@atdot.net>2019-11-18 10:16:11 +0900
commit71fee9bc720ba7a117062bf3f78b6086527b656c (patch)
tree85443e3fbe9cfc0676a807a327e12b814fb20bf5 /compile.c
parent93ce4f1cd7c96f0fdbeebc87a9fa64d07cede729 (diff)
downloadruby-71fee9bc720ba7a117062bf3f78b6086527b656c.tar.gz
vm_invoke_builtin_delegate with start index.
opt_invokebuiltin_delegate and opt_invokebuiltin_delegate_leave invokes builtin functions with same parameters of the method. This technique eliminate stack push operations. However, delegation parameters should be completely same as given parameters. (e.g. `def foo(a, b, c) __builtin_foo(a, b, c)` is okay, but __builtin_foo(b, c) is not allowed) This patch relaxes this restriction. ISeq has a local variables table which includes parameters. For example, the method defined as `def foo(a, b, c) x=y=nil`, then local variables table contains [a, b, c, x, y]. If calling builtin-function with arguments which are sub-array of the lvar table, use opt_invokebuiltin_delegate instruction with start index. For example, `__builtin_foo(b, c)`, `__builtin_bar(c, x, y)` is okay, and so on.
Diffstat (limited to 'compile.c')
-rw-r--r--compile.c77
1 files changed, 52 insertions, 25 deletions
diff --git a/compile.c b/compile.c
index 7de6068a7d..3cf5bb6680 100644
--- a/compile.c
+++ b/compile.c
@@ -6762,39 +6762,65 @@ iseq_builtin_function_name(ID mid)
}
static int
-delegate_call_p(const rb_iseq_t *iseq, unsigned int argc, const LINK_ANCHOR *args)
+delegate_call_p(const rb_iseq_t *iseq, unsigned int argc, const LINK_ANCHOR *args, unsigned int *pstart_index)
{
+
if (argc == 0) {
+ *pstart_index = 0;
return TRUE;
}
- else if (argc == iseq->body->param.size) {
- const LINK_ELEMENT *elem = FIRST_ELEMENT(args);
-
- for (unsigned int i=0; i<argc; i++) {
- if (elem->type == ISEQ_ELEMENT_INSN &&
- INSN_OF(elem) == BIN(getlocal)) {
- int local_index = FIX2INT(OPERAND_AT(elem, 0));
- int local_level = FIX2INT(OPERAND_AT(elem, 1));
- if (local_level == 0) {
- unsigned int index = iseq->body->local_table_size - (local_index - VM_ENV_DATA_SIZE + 1);
-#if 0
- ID param_id = iseq->body->local_table[i];
- fprintf(stderr, "param_id:%s (%d), id:%s (%d) local_index:%d, local_size:%d\n",
- rb_id2name(param_id), i,
- rb_id2name(iseq->body->local_table[index]), index,
- local_index, (int)iseq->body->local_table_size);
-#endif
- if (i == index) {
- elem = elem->next;
- continue; /* for */
+ else if (argc <= iseq->body->local_table_size) {
+ unsigned int start=0;
+
+ // local_table: [p1, p2, p3, l1, l2, l3]
+ // arguments: [p3, l1, l2] -> 2
+ for (start = 0;
+ argc + start <= iseq->body->local_table_size;
+ start++) {
+ const LINK_ELEMENT *elem = FIRST_ELEMENT(args);
+
+ for (unsigned int i=start; i-start<argc; i++) {
+ if (elem->type == ISEQ_ELEMENT_INSN &&
+ INSN_OF(elem) == BIN(getlocal)) {
+ int local_index = FIX2INT(OPERAND_AT(elem, 0));
+ int local_level = FIX2INT(OPERAND_AT(elem, 1));
+
+ if (local_level == 0) {
+ unsigned int index = iseq->body->local_table_size - (local_index - VM_ENV_DATA_SIZE + 1);
+ if (0) { // for debug
+ fprintf(stderr, "lvar:%s (%d), id:%s (%d) local_index:%d, local_size:%d\n",
+ rb_id2name(iseq->body->local_table[i]), i,
+ rb_id2name(iseq->body->local_table[index]), index,
+ local_index, (int)iseq->body->local_table_size);
+ }
+ if (i == index) {
+ elem = elem->next;
+ continue; /* for */
+ }
+ else {
+ goto next;
+ }
+ }
+ else {
+ goto fail; // level != 0 is unsupport
}
}
+ else {
+ goto fail; // insn is not a getlocal
+ }
}
- return FALSE;
+ goto success;
+ next:;
}
+ fail:
+ return FALSE;
+ success:
+ *pstart_index = start;
return TRUE;
}
- return FALSE;
+ else {
+ return FALSE;
+ }
}
static int
@@ -6924,8 +6950,9 @@ compile_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, in
return COMPILE_NG;
}
- if (delegate_call_p(iseq, FIX2INT(argc), args)) {
- ADD_INSN1(ret, line, opt_invokebuiltin_delegate, bf);
+ unsigned int start_index;
+ if (delegate_call_p(iseq, FIX2INT(argc), args, &start_index)) {
+ ADD_INSN2(ret, line, opt_invokebuiltin_delegate, bf, INT2FIX(start_index));
}
else {
ADD_SEQ(ret, args);