зеркало из https://github.com/github/ruby.git
fix passing wrong `passed_bmethod_me`.
* vm_core.h: remove `rb_execution_context_t::passed_bmethod_me` and fix functions to pass the `me` directly. `passed_bmethod_me` was used to make bmethod (methods defined by `defined_method`). `rb_vm_invoke_bmethod` invoke `Proc` with `me` information as method frame (`lambda` frame, actually). If the proc call is not bmethod call, `passed_bmethod_me` should be NULL. However, there is a bug which passes wrong `me` for normal block call. http://ci.rvm.jp/results/trunk-asserts@silicon-docker/1449470 This is because wrong `me` was remained in `passed_bmethod_me` (and used incorrectly it after collected by GC). We need to clear `passed_bmethod_me` just after bmethod call, but clearing is not enough. To solve this issue, I removed `passed_bmethod_me` and pass `me` information as a function parameter of `rb_vm_invoke_bmethod`, `invoke_block_from_c_proc` and `invoke_iseq_block_from_c` in vm.c. * vm.c (invoke_iseq_block_from_c): the number of parameters is too long so that I try to specify `ALWAYS_INLINE`. * vm.c (invoke_block_from_c_proc): ditto. * vm_insnhelper.c (vm_yield_with_cfunc): now there are no pathes to use bmethod here. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@65636 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
Родитель
e3cfb1f3ca
Коммит
3cb6952f12
35
vm.c
35
vm.c
|
@ -299,7 +299,9 @@ static void vm_collect_usage_register(int reg, int isset);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static VALUE vm_make_env_object(const rb_execution_context_t *ec, rb_control_frame_t *cfp);
|
static VALUE vm_make_env_object(const rb_execution_context_t *ec, rb_control_frame_t *cfp);
|
||||||
extern VALUE rb_vm_invoke_bmethod(rb_execution_context_t *ec, rb_proc_t *proc, VALUE self, int argc, const VALUE *argv, VALUE block_handler);
|
extern VALUE rb_vm_invoke_bmethod(rb_execution_context_t *ec, rb_proc_t *proc, VALUE self,
|
||||||
|
int argc, const VALUE *argv, VALUE block_handler,
|
||||||
|
const rb_callable_method_entry_t *me);
|
||||||
static VALUE vm_invoke_proc(rb_execution_context_t *ec, rb_proc_t *proc, VALUE self, int argc, const VALUE *argv, VALUE block_handler);
|
static VALUE vm_invoke_proc(rb_execution_context_t *ec, rb_proc_t *proc, VALUE self, int argc, const VALUE *argv, VALUE block_handler);
|
||||||
|
|
||||||
static VALUE rb_block_param_proxy;
|
static VALUE rb_block_param_proxy;
|
||||||
|
@ -1031,18 +1033,22 @@ invoke_bmethod(rb_execution_context_t *ec, const rb_iseq_t *iseq, VALUE self, co
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE(static inline VALUE
|
||||||
|
invoke_iseq_block_from_c(rb_execution_context_t *ec, const struct rb_captured_block *captured,
|
||||||
|
VALUE self, int argc, const VALUE *argv, VALUE passed_block_handler,
|
||||||
|
const rb_cref_t *cref, int is_lambda, const rb_callable_method_entry_t *me));
|
||||||
|
|
||||||
static inline VALUE
|
static inline VALUE
|
||||||
invoke_iseq_block_from_c(rb_execution_context_t *ec, const struct rb_captured_block *captured,
|
invoke_iseq_block_from_c(rb_execution_context_t *ec, const struct rb_captured_block *captured,
|
||||||
VALUE self, int argc, const VALUE *argv, VALUE passed_block_handler,
|
VALUE self, int argc, const VALUE *argv, VALUE passed_block_handler,
|
||||||
const rb_cref_t *cref, int is_lambda)
|
const rb_cref_t *cref, int is_lambda, const rb_callable_method_entry_t *me)
|
||||||
{
|
{
|
||||||
const rb_iseq_t *iseq = rb_iseq_check(captured->code.iseq);
|
const rb_iseq_t *iseq = rb_iseq_check(captured->code.iseq);
|
||||||
int i, opt_pc;
|
int i, opt_pc;
|
||||||
VALUE type = VM_FRAME_MAGIC_BLOCK | (is_lambda ? VM_FRAME_FLAG_LAMBDA : 0);
|
VALUE type = VM_FRAME_MAGIC_BLOCK | (is_lambda ? VM_FRAME_FLAG_LAMBDA : 0);
|
||||||
rb_control_frame_t *cfp = ec->cfp;
|
rb_control_frame_t *cfp = ec->cfp;
|
||||||
VALUE *sp = cfp->sp;
|
VALUE *sp = cfp->sp;
|
||||||
const rb_callable_method_entry_t *me = ec->passed_bmethod_me;
|
|
||||||
ec->passed_bmethod_me = NULL;
|
|
||||||
stack_check(ec);
|
stack_check(ec);
|
||||||
|
|
||||||
CHECK_VM_STACK_OVERFLOW(cfp, argc);
|
CHECK_VM_STACK_OVERFLOW(cfp, argc);
|
||||||
|
@ -1076,7 +1082,7 @@ invoke_block_from_c_bh(rb_execution_context_t *ec, VALUE block_handler,
|
||||||
const struct rb_captured_block *captured = VM_BH_TO_ISEQ_BLOCK(block_handler);
|
const struct rb_captured_block *captured = VM_BH_TO_ISEQ_BLOCK(block_handler);
|
||||||
return invoke_iseq_block_from_c(ec, captured, captured->self,
|
return invoke_iseq_block_from_c(ec, captured, captured->self,
|
||||||
argc, argv, passed_block_handler,
|
argc, argv, passed_block_handler,
|
||||||
cref, is_lambda);
|
cref, is_lambda, NULL);
|
||||||
}
|
}
|
||||||
case block_handler_type_ifunc:
|
case block_handler_type_ifunc:
|
||||||
return vm_yield_with_cfunc(ec, VM_BH_TO_IFUNC_BLOCK(block_handler),
|
return vm_yield_with_cfunc(ec, VM_BH_TO_IFUNC_BLOCK(block_handler),
|
||||||
|
@ -1139,17 +1145,24 @@ vm_yield_force_blockarg(rb_execution_context_t *ec, VALUE args)
|
||||||
VM_BLOCK_HANDLER_NONE, NULL, FALSE, TRUE);
|
VM_BLOCK_HANDLER_NONE, NULL, FALSE, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE(static inline VALUE
|
||||||
|
invoke_block_from_c_proc(rb_execution_context_t *ec, const rb_proc_t *proc,
|
||||||
|
VALUE self, int argc, const VALUE *argv,
|
||||||
|
VALUE passed_block_handler, int is_lambda,
|
||||||
|
const rb_callable_method_entry_t *me));
|
||||||
|
|
||||||
static inline VALUE
|
static inline VALUE
|
||||||
invoke_block_from_c_proc(rb_execution_context_t *ec, const rb_proc_t *proc,
|
invoke_block_from_c_proc(rb_execution_context_t *ec, const rb_proc_t *proc,
|
||||||
VALUE self, int argc, const VALUE *argv,
|
VALUE self, int argc, const VALUE *argv,
|
||||||
VALUE passed_block_handler, int is_lambda)
|
VALUE passed_block_handler, int is_lambda,
|
||||||
|
const rb_callable_method_entry_t *me)
|
||||||
{
|
{
|
||||||
const struct rb_block *block = &proc->block;
|
const struct rb_block *block = &proc->block;
|
||||||
|
|
||||||
again:
|
again:
|
||||||
switch (vm_block_type(block)) {
|
switch (vm_block_type(block)) {
|
||||||
case block_type_iseq:
|
case block_type_iseq:
|
||||||
return invoke_iseq_block_from_c(ec, &block->as.captured, self, argc, argv, passed_block_handler, NULL, is_lambda);
|
return invoke_iseq_block_from_c(ec, &block->as.captured, self, argc, argv, passed_block_handler, NULL, is_lambda, me);
|
||||||
case block_type_ifunc:
|
case block_type_ifunc:
|
||||||
return vm_yield_with_cfunc(ec, &block->as.captured, self, argc, argv, passed_block_handler);
|
return vm_yield_with_cfunc(ec, &block->as.captured, self, argc, argv, passed_block_handler);
|
||||||
case block_type_symbol:
|
case block_type_symbol:
|
||||||
|
@ -1167,14 +1180,14 @@ static VALUE
|
||||||
vm_invoke_proc(rb_execution_context_t *ec, rb_proc_t *proc, VALUE self,
|
vm_invoke_proc(rb_execution_context_t *ec, rb_proc_t *proc, VALUE self,
|
||||||
int argc, const VALUE *argv, VALUE passed_block_handler)
|
int argc, const VALUE *argv, VALUE passed_block_handler)
|
||||||
{
|
{
|
||||||
return invoke_block_from_c_proc(ec, proc, self, argc, argv, passed_block_handler, proc->is_lambda);
|
return invoke_block_from_c_proc(ec, proc, self, argc, argv, passed_block_handler, proc->is_lambda, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
MJIT_FUNC_EXPORTED VALUE
|
MJIT_FUNC_EXPORTED VALUE
|
||||||
rb_vm_invoke_bmethod(rb_execution_context_t *ec, rb_proc_t *proc, VALUE self,
|
rb_vm_invoke_bmethod(rb_execution_context_t *ec, rb_proc_t *proc, VALUE self,
|
||||||
int argc, const VALUE *argv, VALUE block_handler)
|
int argc, const VALUE *argv, VALUE block_handler, const rb_callable_method_entry_t *me)
|
||||||
{
|
{
|
||||||
return invoke_block_from_c_proc(ec, proc, self, argc, argv, block_handler, TRUE);
|
return invoke_block_from_c_proc(ec, proc, self, argc, argv, block_handler, TRUE, me);
|
||||||
}
|
}
|
||||||
|
|
||||||
MJIT_FUNC_EXPORTED VALUE
|
MJIT_FUNC_EXPORTED VALUE
|
||||||
|
@ -1185,7 +1198,7 @@ rb_vm_invoke_proc(rb_execution_context_t *ec, rb_proc_t *proc,
|
||||||
vm_block_handler_verify(passed_block_handler);
|
vm_block_handler_verify(passed_block_handler);
|
||||||
|
|
||||||
if (proc->is_from_method) {
|
if (proc->is_from_method) {
|
||||||
return rb_vm_invoke_bmethod(ec, proc, self, argc, argv, passed_block_handler);
|
return rb_vm_invoke_bmethod(ec, proc, self, argc, argv, passed_block_handler, NULL);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return vm_invoke_proc(ec, proc, self, argc, argv, passed_block_handler);
|
return vm_invoke_proc(ec, proc, self, argc, argv, passed_block_handler);
|
||||||
|
|
|
@ -858,7 +858,6 @@ typedef struct rb_execution_context_struct {
|
||||||
/* temporary places */
|
/* temporary places */
|
||||||
VALUE errinfo;
|
VALUE errinfo;
|
||||||
VALUE passed_block_handler; /* for rb_iterate */
|
VALUE passed_block_handler; /* for rb_iterate */
|
||||||
const rb_callable_method_entry_t *passed_bmethod_me; /* for bmethod */
|
|
||||||
|
|
||||||
uint8_t raised_flag; /* only 3 bits needed */
|
uint8_t raised_flag; /* only 3 bits needed */
|
||||||
|
|
||||||
|
|
|
@ -1943,9 +1943,8 @@ vm_call_bmethod_body(rb_execution_context_t *ec, struct rb_calling_info *calling
|
||||||
VALUE val;
|
VALUE val;
|
||||||
|
|
||||||
/* control block frame */
|
/* control block frame */
|
||||||
ec->passed_bmethod_me = cc->me;
|
|
||||||
GetProcPtr(cc->me->def->body.proc, proc);
|
GetProcPtr(cc->me->def->body.proc, proc);
|
||||||
val = rb_vm_invoke_bmethod(ec, proc, calling->recv, calling->argc, argv, calling->block_handler);
|
val = rb_vm_invoke_bmethod(ec, proc, calling->recv, calling->argc, argv, calling->block_handler, cc->me);
|
||||||
|
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
@ -2517,8 +2516,6 @@ vm_yield_with_cfunc(rb_execution_context_t *ec,
|
||||||
int is_lambda = FALSE; /* TODO */
|
int is_lambda = FALSE; /* TODO */
|
||||||
VALUE val, arg, blockarg;
|
VALUE val, arg, blockarg;
|
||||||
const struct vm_ifunc *ifunc = captured->code.ifunc;
|
const struct vm_ifunc *ifunc = captured->code.ifunc;
|
||||||
const rb_callable_method_entry_t *me = ec->passed_bmethod_me;
|
|
||||||
ec->passed_bmethod_me = NULL;
|
|
||||||
|
|
||||||
if (is_lambda) {
|
if (is_lambda) {
|
||||||
arg = rb_ary_new4(argc, argv);
|
arg = rb_ary_new4(argc, argv);
|
||||||
|
@ -2536,7 +2533,7 @@ vm_yield_with_cfunc(rb_execution_context_t *ec,
|
||||||
VM_FRAME_MAGIC_IFUNC | VM_FRAME_FLAG_CFRAME,
|
VM_FRAME_MAGIC_IFUNC | VM_FRAME_FLAG_CFRAME,
|
||||||
self,
|
self,
|
||||||
VM_GUARDED_PREV_EP(captured->ep),
|
VM_GUARDED_PREV_EP(captured->ep),
|
||||||
(VALUE)me,
|
Qfalse,
|
||||||
0, ec->cfp->sp, 0, 0);
|
0, ec->cfp->sp, 0, 0);
|
||||||
val = (*ifunc->func)(arg, ifunc->data, argc, argv, blockarg);
|
val = (*ifunc->func)(arg, ifunc->data, argc, argv, blockarg);
|
||||||
rb_vm_pop_frame(ec);
|
rb_vm_pop_frame(ec);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче