зеркало из https://github.com/github/ruby.git
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.
This commit is contained in:
Родитель
93ce4f1cd7
Коммит
71fee9bc72
75
compile.c
75
compile.c
|
@ -6762,39 +6762,65 @@ iseq_builtin_function_name(ID mid)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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) {
|
if (argc == 0) {
|
||||||
|
*pstart_index = 0;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
else if (argc == iseq->body->param.size) {
|
else if (argc <= iseq->body->local_table_size) {
|
||||||
const LINK_ELEMENT *elem = FIRST_ELEMENT(args);
|
unsigned int start=0;
|
||||||
|
|
||||||
for (unsigned int i=0; i<argc; i++) {
|
// local_table: [p1, p2, p3, l1, l2, l3]
|
||||||
if (elem->type == ISEQ_ELEMENT_INSN &&
|
// arguments: [p3, l1, l2] -> 2
|
||||||
INSN_OF(elem) == BIN(getlocal)) {
|
for (start = 0;
|
||||||
int local_index = FIX2INT(OPERAND_AT(elem, 0));
|
argc + start <= iseq->body->local_table_size;
|
||||||
int local_level = FIX2INT(OPERAND_AT(elem, 1));
|
start++) {
|
||||||
if (local_level == 0) {
|
const LINK_ELEMENT *elem = FIRST_ELEMENT(args);
|
||||||
unsigned int index = iseq->body->local_table_size - (local_index - VM_ENV_DATA_SIZE + 1);
|
|
||||||
#if 0
|
for (unsigned int i=start; i-start<argc; i++) {
|
||||||
ID param_id = iseq->body->local_table[i];
|
if (elem->type == ISEQ_ELEMENT_INSN &&
|
||||||
fprintf(stderr, "param_id:%s (%d), id:%s (%d) local_index:%d, local_size:%d\n",
|
INSN_OF(elem) == BIN(getlocal)) {
|
||||||
rb_id2name(param_id), i,
|
int local_index = FIX2INT(OPERAND_AT(elem, 0));
|
||||||
rb_id2name(iseq->body->local_table[index]), index,
|
int local_level = FIX2INT(OPERAND_AT(elem, 1));
|
||||||
local_index, (int)iseq->body->local_table_size);
|
|
||||||
#endif
|
if (local_level == 0) {
|
||||||
if (i == index) {
|
unsigned int index = iseq->body->local_table_size - (local_index - VM_ENV_DATA_SIZE + 1);
|
||||||
elem = elem->next;
|
if (0) { // for debug
|
||||||
continue; /* for */
|
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 TRUE;
|
||||||
}
|
}
|
||||||
return FALSE;
|
else {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -6924,8 +6950,9 @@ compile_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, in
|
||||||
return COMPILE_NG;
|
return COMPILE_NG;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (delegate_call_p(iseq, FIX2INT(argc), args)) {
|
unsigned int start_index;
|
||||||
ADD_INSN1(ret, line, opt_invokebuiltin_delegate, bf);
|
if (delegate_call_p(iseq, FIX2INT(argc), args, &start_index)) {
|
||||||
|
ADD_INSN2(ret, line, opt_invokebuiltin_delegate, bf, INT2FIX(start_index));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ADD_SEQ(ret, args);
|
ADD_SEQ(ret, args);
|
||||||
|
|
10
insns.def
10
insns.def
|
@ -1492,26 +1492,26 @@ invokebuiltin
|
||||||
/* call specific function with args (same parameters) */
|
/* call specific function with args (same parameters) */
|
||||||
DEFINE_INSN
|
DEFINE_INSN
|
||||||
opt_invokebuiltin_delegate
|
opt_invokebuiltin_delegate
|
||||||
(RB_BUILTIN bf)
|
(RB_BUILTIN bf, rb_num_t index)
|
||||||
()
|
()
|
||||||
(VALUE ret)
|
(VALUE ret)
|
||||||
// attr bool leaf = false; /* anything can happen inside */
|
// attr bool leaf = false; /* anything can happen inside */
|
||||||
{
|
{
|
||||||
ret = vm_invoke_builtin_delegate(ec, reg_cfp, bf);
|
ret = vm_invoke_builtin_delegate(ec, reg_cfp, bf, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* call specific function with args (same parameters) and leave */
|
/* call specific function with args (same parameters) and leave */
|
||||||
DEFINE_INSN
|
DEFINE_INSN
|
||||||
opt_invokebuiltin_delegate_leave
|
opt_invokebuiltin_delegate_leave
|
||||||
(RB_BUILTIN bf)
|
(RB_BUILTIN bf, rb_num_t index)
|
||||||
()
|
()
|
||||||
(VALUE val)
|
(VALUE val)
|
||||||
// attr bool leaf = false; /* anything can happen inside */
|
// attr bool leaf = false; /* anything can happen inside */
|
||||||
{
|
{
|
||||||
val = vm_invoke_builtin_delegate(ec, reg_cfp, bf);
|
val = vm_invoke_builtin_delegate(ec, reg_cfp, bf, index);
|
||||||
|
|
||||||
/* leave fastpath */
|
/* leave fastpath */
|
||||||
/* TracePoint/return should fallback this insn to invokecfuncwparam */
|
/* TracePoint/return should fallback this insn to opt_invokebuiltin_delegate */
|
||||||
if (vm_pop_frame(ec, GET_CFP(), GET_EP())) {
|
if (vm_pop_frame(ec, GET_CFP(), GET_EP())) {
|
||||||
#if OPT_CALL_THREADED_CODE
|
#if OPT_CALL_THREADED_CODE
|
||||||
rb_ec_thread_ptr(ec)->retval = val;
|
rb_ec_thread_ptr(ec)->retval = val;
|
||||||
|
|
|
@ -21,6 +21,11 @@ rb_load_with_builtin_functions(const char *feature_name, const struct rb_builtin
|
||||||
|
|
||||||
rb_ast_dispose(ast);
|
rb_ast_dispose(ast);
|
||||||
|
|
||||||
|
// for debug
|
||||||
|
if (0 && strcmp("prelude", feature_name) == 0) {
|
||||||
|
rb_io_write(rb_stdout, rb_iseq_disasm((const rb_iseq_t *)iseq));
|
||||||
|
}
|
||||||
|
|
||||||
// register (loaded iseq will not be freed)
|
// register (loaded iseq will not be freed)
|
||||||
st_insert(loaded_builtin_table, (st_data_t)feature_name, (st_data_t)iseq);
|
st_insert(loaded_builtin_table, (st_data_t)feature_name, (st_data_t)iseq);
|
||||||
rb_gc_register_mark_object((VALUE)iseq);
|
rb_gc_register_mark_object((VALUE)iseq);
|
||||||
|
|
|
@ -4989,10 +4989,18 @@ vm_invoke_builtin(rb_execution_context_t *ec, rb_control_frame_t *cfp, const str
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
vm_invoke_builtin_delegate(rb_execution_context_t *ec, rb_control_frame_t *cfp, const struct rb_builtin_function *bf)
|
vm_invoke_builtin_delegate(rb_execution_context_t *ec, rb_control_frame_t *cfp, const struct rb_builtin_function *bf, int start_index)
|
||||||
{
|
{
|
||||||
const VALUE *argv = cfp->ep - cfp->iseq->body->local_table_size - VM_ENV_DATA_SIZE + 1;
|
if (0) { // debug print
|
||||||
// fprintf(stderr, "%s %s(%d):%p\n", __func__, bf->name, bf->argc, bf->func_ptr);
|
fprintf(stderr, "vm_invoke_builtin_delegate: passing -> ");
|
||||||
|
for (int i=0; i<bf->argc; i++) {
|
||||||
|
fprintf(stderr, ":%s ", rb_id2name(cfp->iseq->body->local_table[i+start_index]));
|
||||||
|
}
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
fprintf(stderr, "%s %s(%d):%p\n", __func__, bf->name, bf->argc, bf->func_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
const VALUE *argv = cfp->ep - cfp->iseq->body->local_table_size - VM_ENV_DATA_SIZE + 1 + start_index;
|
||||||
return invoke_bf(ec, cfp, bf, argv);
|
return invoke_bf(ec, cfp, bf, argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче