summaryrefslogtreecommitdiff
path: root/vm_insnhelper.c
diff options
context:
space:
mode:
authorko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2015-10-23 17:53:35 +0000
committerko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2015-10-23 17:53:35 +0000
commitf9697c5637f84d1ec9cb46a2115c76c7971aeb0f (patch)
tree7991edac0f5872f2c8ac7aecffed6e87226518ed /vm_insnhelper.c
parent1e0600324b651310396329343fd407507a533318 (diff)
* vm_insnhelper.c: introduce new call handler for simple ISeqs.
vm_call_iseq_setup_normal_0start() is simple, however it has some loops/conditions depends on ISeq::param.size and ISeq::local_size (in vm_push_frame(), inlined into this function). There are many simple methods which has a few parameters and local variables. So that this patch introduces several special functions generated in vm_call_iseq_optimized.inc by tool/mk_call_iseq_optimized.rb. This script makes vm_call_iseq_setup_normal_0start_Xparams_Ylocals() where X is 0 to 3 and Y is 1 to 6 (as current setting). In this case, X * Y = 24 functions are created. These functions creates fast method dispatch by inlining vm_push_frame() with immediate params/locals sizes. On my laptop, we can have the following results. vm2_method* 1.083 (8.3% faster) vm2_poly_method* 0.961 (3.4% slower) It shows 8.3% faster for inner loop method dispatch (hit inline cache), but 3.4% slower when inline cache miss because we need to find a suitable call handler. * common.mk: add a rule for vm_call_iseq_optimized.inc. * tool/mk_call_iseq_optimized.rb: added. * vm.c: include vm_call_iseq_optimized.inc. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@52254 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'vm_insnhelper.c')
-rw-r--r--vm_insnhelper.c84
1 files changed, 46 insertions, 38 deletions
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index ae636a964e..cec303767f 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -1235,17 +1235,17 @@ vm_base_ptr(rb_control_frame_t *cfp)
#include "vm_args.c"
-static inline VALUE vm_call_iseq_setup_2(rb_thread_t *th, rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc, int opt_pc);
-static inline VALUE vm_call_iseq_setup_normal(rb_thread_t *th, rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc, int opt_pc);
+static inline VALUE vm_call_iseq_setup_2(rb_thread_t *th, rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc, int opt_pc, int param_size, int local_size);
+static inline VALUE vm_call_iseq_setup_normal(rb_thread_t *th, rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc, int opt_pc, int param_size, int local_size);
static inline VALUE vm_call_iseq_setup_tailcall(rb_thread_t *th, rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc, int opt_pc);
-static VALUE vm_call_iseq_setup_normal_0start(rb_thread_t *th, rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc);
-static VALUE vm_call_iseq_setup_tailcall_0start(rb_thread_t *th, rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc);
-
static VALUE vm_call_super_method(rb_thread_t *th, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc);
static VALUE vm_call_method_nome(rb_thread_t *th, rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc);
static VALUE vm_call_method_each_type(rb_thread_t *th, rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc);
static inline VALUE vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc);
+typedef VALUE (*vm_call_handler)(struct rb_thread_struct *th, struct rb_control_frame_struct *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc);
+static vm_call_handler vm_call_iseq_setup_func(const struct rb_call_info *ci, const int param_size, const int local_size);
+
static rb_method_definition_t *method_definition_create(rb_method_type_t type, ID mid);
static void method_definition_set(const rb_method_entry_t *me, rb_method_definition_t *def, void *opts);
static int rb_method_definition_eq(const rb_method_definition_t *d1, const rb_method_definition_t *d2);
@@ -1332,8 +1332,33 @@ vm_callee_setup_block_arg(rb_thread_t *th, struct rb_calling_info *calling, cons
}
}
+static const rb_iseq_t *
+def_iseq_ptr(rb_method_definition_t *def)
+{
+#if VM_CHECK_MODE > 0
+ if (def->type != VM_METHOD_TYPE_ISEQ) rb_bug("def_iseq_ptr: not iseq (%d)", def->type);
+#endif
+ return def->body.iseq.iseqptr;
+}
+
+static VALUE
+vm_call_iseq_setup_tailcall_0start(rb_thread_t *th, rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc)
+{
+ return vm_call_iseq_setup_tailcall(th, cfp, calling, ci, cc, 0);
+}
+
+static VALUE
+vm_call_iseq_setup_normal_0start(rb_thread_t *th, rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc)
+{
+ const rb_iseq_t *iseq = def_iseq_ptr(cc->me->def);
+ int param = iseq->body->param.size;
+ int local = iseq->body->local_size;
+ return vm_call_iseq_setup_normal(th, cfp, calling, ci, cc, 0, param, local);
+}
+
static inline int
-vm_callee_setup_arg(rb_thread_t *th, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc, const rb_iseq_t *iseq, VALUE *argv)
+vm_callee_setup_arg(rb_thread_t *th, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc,
+ const rb_iseq_t *iseq, VALUE *argv, int param_size, int local_size)
{
if (LIKELY(simple_iseq_p(iseq))) {
rb_control_frame_t *cfp = th->cfp;
@@ -1344,9 +1369,7 @@ vm_callee_setup_arg(rb_thread_t *th, struct rb_calling_info *calling, const stru
argument_arity_error(th, iseq, calling->argc, iseq->body->param.lead_num, iseq->body->param.lead_num);
}
- CI_SET_FASTPATH(cc,
- (UNLIKELY(ci->flag & VM_CALL_TAILCALL) ? vm_call_iseq_setup_tailcall_0start :
- vm_call_iseq_setup_normal_0start),
+ CI_SET_FASTPATH(cc, vm_call_iseq_setup_func(ci, param_size, local_size),
(!IS_ARGS_SPLAT(ci) && !IS_ARGS_KEYWORD(ci) &&
!(METHOD_ENTRY_VISI(cc->me) == METHOD_VISI_PROTECTED)));
return 0;
@@ -1356,27 +1379,22 @@ vm_callee_setup_arg(rb_thread_t *th, struct rb_calling_info *calling, const stru
}
}
-static const rb_iseq_t *
-def_iseq_ptr(rb_method_definition_t *def)
-{
-#if VM_CHECK_MODE > 0
- if (def->type != VM_METHOD_TYPE_ISEQ) rb_bug("def_iseq_ptr: not iseq (%d)", def->type);
-#endif
- return def->body.iseq.iseqptr;
-}
-
static VALUE
vm_call_iseq_setup(rb_thread_t *th, rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc)
{
- int opt_pc = vm_callee_setup_arg(th, calling, ci, cc, def_iseq_ptr(cc->me->def), cfp->sp - calling->argc);
- return vm_call_iseq_setup_2(th, cfp, calling, ci, cc, opt_pc);
+ const rb_iseq_t *iseq = def_iseq_ptr(cc->me->def);
+ const int param_size = iseq->body->param.size;
+ const int local_size = iseq->body->local_size;
+ const int opt_pc = vm_callee_setup_arg(th, calling, ci, cc, def_iseq_ptr(cc->me->def), cfp->sp - calling->argc, param_size, local_size);
+ return vm_call_iseq_setup_2(th, cfp, calling, ci, cc, opt_pc, param_size, local_size);
}
static inline VALUE
-vm_call_iseq_setup_2(rb_thread_t *th, rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc, int opt_pc)
+vm_call_iseq_setup_2(rb_thread_t *th, rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc,
+ int opt_pc, int param_size, int local_size)
{
if (LIKELY(!(ci->flag & VM_CALL_TAILCALL))) {
- return vm_call_iseq_setup_normal(th, cfp, calling, ci, cc, opt_pc);
+ return vm_call_iseq_setup_normal(th, cfp, calling, ci, cc, opt_pc, param_size, local_size);
}
else {
return vm_call_iseq_setup_tailcall(th, cfp, calling, ci, cc, opt_pc);
@@ -1384,24 +1402,26 @@ vm_call_iseq_setup_2(rb_thread_t *th, rb_control_frame_t *cfp, struct rb_calling
}
static inline VALUE
-vm_call_iseq_setup_normal(rb_thread_t *th, rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc, int opt_pc)
+vm_call_iseq_setup_normal(rb_thread_t *th, rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc,
+ int opt_pc, int param_size, int local_size)
{
const rb_callable_method_entry_t *me = cc->me;
const rb_iseq_t *iseq = def_iseq_ptr(me->def);
VALUE *argv = cfp->sp - calling->argc;
- VALUE *sp = argv + iseq->body->param.size;
+ VALUE *sp = argv + param_size;
cfp->sp = argv - 1 /* recv */;
vm_push_frame(th, iseq, VM_FRAME_MAGIC_METHOD, calling->recv,
VM_ENVVAL_BLOCK_PTR(calling->blockptr), (VALUE)me,
iseq->body->iseq_encoded + opt_pc, sp,
- iseq->body->local_size - iseq->body->param.size,
+ local_size - param_size,
iseq->body->stack_max);
return Qundef;
}
static inline VALUE
-vm_call_iseq_setup_tailcall(rb_thread_t *th, rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc, int opt_pc)
+vm_call_iseq_setup_tailcall(rb_thread_t *th, rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc,
+ int opt_pc)
{
unsigned int i;
VALUE *argv = cfp->sp - calling->argc;
@@ -1437,18 +1457,6 @@ vm_call_iseq_setup_tailcall(rb_thread_t *th, rb_control_frame_t *cfp, struct rb_
}
static VALUE
-vm_call_iseq_setup_normal_0start(rb_thread_t *th, rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc)
-{
- return vm_call_iseq_setup_normal(th, cfp, calling, ci, cc, 0);
-}
-
-static VALUE
-vm_call_iseq_setup_tailcall_0start(rb_thread_t *th, rb_control_frame_t *cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, struct rb_call_cache *cc)
-{
- return vm_call_iseq_setup_tailcall(th, cfp, calling, ci, cc, 0);
-}
-
-static VALUE
call_cfunc_m2(VALUE (*func)(ANYARGS), VALUE recv, int argc, const VALUE *argv)
{
return (*func)(recv, rb_ary_new4(argc, argv));