зеркало из https://github.com/github/ruby.git
vm_eval.c: cache results
* vm_eval.c (check_funcall_failed, check_funcall_missing): cache results of respond_to? and respond_to_missing?, and search a pulibc method only for compatibility with rb_respond_to. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51665 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
Родитель
1f557eaea1
Коммит
2f8a4d317f
|
@ -1,3 +1,9 @@
|
|||
Sat Aug 22 15:43:12 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||
|
||||
* vm_eval.c (check_funcall_failed, check_funcall_missing): cache
|
||||
results of respond_to? and respond_to_missing?, and search a
|
||||
pulibc method only for compatibility with rb_respond_to.
|
||||
|
||||
Sat Aug 22 08:23:32 2015 Koichi Sasada <ko1@atdot.net>
|
||||
|
||||
* ext/thread/thread.c: move definitions of Queue, SizedQueue
|
||||
|
|
46
vm_eval.c
46
vm_eval.c
|
@ -352,6 +352,8 @@ struct rescue_funcall_args {
|
|||
VALUE recv;
|
||||
ID mid;
|
||||
const rb_method_entry_t *me;
|
||||
unsigned int respond: 1;
|
||||
unsigned int respond_to_missing: 1;
|
||||
int argc;
|
||||
const VALUE *argv;
|
||||
};
|
||||
|
@ -364,10 +366,27 @@ check_funcall_exec(struct rescue_funcall_args *args)
|
|||
args->me, args->argc, args->argv);
|
||||
}
|
||||
|
||||
#define PRIV Qfalse /* TODO: for rubyspec now, should be Qtrue */
|
||||
|
||||
static VALUE
|
||||
check_funcall_failed(struct rescue_funcall_args *args, VALUE e)
|
||||
{
|
||||
if (rb_respond_to(args->recv, args->mid)) {
|
||||
int ret = args->respond;
|
||||
if (!ret) {
|
||||
switch (rb_method_boundp(args->defined_class, args->mid,
|
||||
BOUND_PRIVATE|BOUND_RESPONDS)) {
|
||||
case 2:
|
||||
ret = TRUE;
|
||||
break;
|
||||
case 0:
|
||||
ret = args->respond_to_missing;
|
||||
break;
|
||||
default:
|
||||
ret = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret) {
|
||||
rb_exc_raise(e);
|
||||
}
|
||||
return Qundef;
|
||||
|
@ -376,7 +395,7 @@ check_funcall_failed(struct rescue_funcall_args *args, VALUE e)
|
|||
static int
|
||||
check_funcall_respond_to(rb_thread_t *th, VALUE klass, VALUE recv, ID mid)
|
||||
{
|
||||
return vm_respond_to(th, klass, recv, mid, 1);
|
||||
return vm_respond_to(th, klass, recv, mid, TRUE);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -386,12 +405,19 @@ check_funcall_callable(rb_thread_t *th, const rb_callable_method_entry_t *me)
|
|||
}
|
||||
|
||||
static VALUE
|
||||
check_funcall_missing(rb_thread_t *th, VALUE klass, VALUE recv, ID mid, int argc, const VALUE *argv)
|
||||
check_funcall_missing(rb_thread_t *th, VALUE klass, VALUE recv, ID mid, int argc, const VALUE *argv, int respond)
|
||||
{
|
||||
struct rescue_funcall_args args;
|
||||
const rb_method_entry_t *me;
|
||||
VALUE ret = Qundef;
|
||||
const rb_method_entry_t *const me =
|
||||
method_entry_get(klass, idMethodMissing, &args.defined_class);
|
||||
|
||||
ret = basic_obj_respond_to_missing(th, klass, recv,
|
||||
ID2SYM(mid), PRIV);
|
||||
if (!RTEST(ret)) return Qundef;
|
||||
args.respond = respond > 0;
|
||||
args.respond_to_missing = (ret != Qundef);
|
||||
ret = Qundef;
|
||||
me = method_entry_get(klass, idMethodMissing, &args.defined_class);
|
||||
if (me && !METHOD_ENTRY_BASIC(me)) {
|
||||
VALUE argbuf, *new_args = ALLOCV_N(VALUE, argbuf, argc+1);
|
||||
|
||||
|
@ -418,13 +444,14 @@ rb_check_funcall(VALUE recv, ID mid, int argc, const VALUE *argv)
|
|||
VALUE klass = CLASS_OF(recv);
|
||||
const rb_callable_method_entry_t *me;
|
||||
rb_thread_t *th = GET_THREAD();
|
||||
int respond = check_funcall_respond_to(th, klass, recv, mid);
|
||||
|
||||
if (!check_funcall_respond_to(th, klass, recv, mid))
|
||||
if (!respond)
|
||||
return Qundef;
|
||||
|
||||
me = rb_search_method_entry(recv, mid);
|
||||
if (!check_funcall_callable(th, me)) {
|
||||
return check_funcall_missing(th, klass, recv, mid, argc, argv);
|
||||
return check_funcall_missing(th, klass, recv, mid, argc, argv, respond);
|
||||
}
|
||||
stack_check();
|
||||
return vm_call0(th, recv, mid, argc, argv, me);
|
||||
|
@ -437,14 +464,15 @@ rb_check_funcall_with_hook(VALUE recv, ID mid, int argc, const VALUE *argv,
|
|||
VALUE klass = CLASS_OF(recv);
|
||||
const rb_callable_method_entry_t *me;
|
||||
rb_thread_t *th = GET_THREAD();
|
||||
int respond = check_funcall_respond_to(th, klass, recv, mid);
|
||||
|
||||
if (!check_funcall_respond_to(th, klass, recv, mid))
|
||||
if (!respond)
|
||||
return Qundef;
|
||||
|
||||
me = rb_search_method_entry(recv, mid);
|
||||
if (!check_funcall_callable(th, me)) {
|
||||
(*hook)(FALSE, recv, mid, argc, argv, arg);
|
||||
return check_funcall_missing(th, klass, recv, mid, argc, argv);
|
||||
return check_funcall_missing(th, klass, recv, mid, argc, argv, respond);
|
||||
}
|
||||
stack_check();
|
||||
(*hook)(TRUE, recv, mid, argc, argv, arg);
|
||||
|
|
22
vm_method.c
22
vm_method.c
|
@ -1832,7 +1832,7 @@ basic_obj_respond_to_missing(rb_thread_t *th, VALUE klass, VALUE obj,
|
|||
const rb_method_entry_t *const me =
|
||||
method_entry_get(klass, rtmid, &defined_class);
|
||||
|
||||
if (!me || METHOD_ENTRY_BASIC(me)) return Qfalse;
|
||||
if (!me || METHOD_ENTRY_BASIC(me)) return Qundef;
|
||||
args[0] = mid;
|
||||
args[1] = priv;
|
||||
return call_method_entry(th, defined_class, obj, rtmid, me, 2, args);
|
||||
|
@ -1842,13 +1842,15 @@ static inline int
|
|||
basic_obj_respond_to(rb_thread_t *th, VALUE obj, ID id, int pub)
|
||||
{
|
||||
VALUE klass = CLASS_OF(obj);
|
||||
VALUE ret;
|
||||
|
||||
switch (rb_method_boundp(klass, id, pub|BOUND_RESPONDS)) {
|
||||
case 2:
|
||||
return FALSE;
|
||||
case 0:
|
||||
return RTEST(basic_obj_respond_to_missing(th, klass, obj, ID2SYM(id),
|
||||
pub ? Qfalse : Qtrue));
|
||||
ret = basic_obj_respond_to_missing(th, klass, obj, ID2SYM(id),
|
||||
pub ? Qfalse : Qtrue);
|
||||
return RTEST(ret) && ret != Qundef;
|
||||
default:
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -1864,7 +1866,7 @@ vm_respond_to(rb_thread_t *th, VALUE klass, VALUE obj, ID id, int priv)
|
|||
|
||||
if (!me) return TRUE;
|
||||
if (METHOD_ENTRY_BASIC(me)) {
|
||||
return basic_obj_respond_to(th, obj, id, !priv);
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
int argc = 1;
|
||||
|
@ -1908,7 +1910,11 @@ vm_respond_to(rb_thread_t *th, VALUE klass, VALUE obj, ID id, int priv)
|
|||
int
|
||||
rb_obj_respond_to(VALUE obj, ID id, int priv)
|
||||
{
|
||||
return vm_respond_to(GET_THREAD(), CLASS_OF(obj), obj, id, priv);
|
||||
rb_thread_t *th = GET_THREAD();
|
||||
VALUE klass = CLASS_OF(obj);
|
||||
int ret = vm_respond_to(th, klass, obj, id, priv);
|
||||
if (ret == -1) ret = basic_obj_respond_to(th, obj, id, !priv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -1947,8 +1953,10 @@ obj_respond_to(int argc, VALUE *argv, VALUE obj)
|
|||
|
||||
rb_scan_args(argc, argv, "11", &mid, &priv);
|
||||
if (!(id = rb_check_id(&mid))) {
|
||||
return basic_obj_respond_to_missing(th, CLASS_OF(obj), obj,
|
||||
rb_to_symbol(mid), priv);
|
||||
VALUE ret = basic_obj_respond_to_missing(th, CLASS_OF(obj), obj,
|
||||
rb_to_symbol(mid), priv);
|
||||
if (ret == Qundef) ret = Qfalse;
|
||||
return ret;
|
||||
}
|
||||
if (basic_obj_respond_to(th, obj, id, !RTEST(priv)))
|
||||
return Qtrue;
|
||||
|
|
Загрузка…
Ссылка в новой задаче