summaryrefslogtreecommitdiff
path: root/vm_method.c
diff options
context:
space:
mode:
author卜部昌平 <shyouhei@ruby-lang.org>2019-09-20 17:01:53 +0900
committer卜部昌平 <shyouhei@ruby-lang.org>2019-09-30 10:26:38 +0900
commitc11c5e69ac66ae10255a20a6b84e481f0423703d (patch)
tree2f627c134096d09e69fba834067605982b28cc44 /vm_method.c
parentcf336082039ae84b5001908f6bb7e04bdda8893e (diff)
refactor split rb_method_definition_set
Did you know that C functions can return structs? That has been true since the beginning, but not that very useful until C99. Now that we can write compound literals, this feature is much easier to use. By allowing struct-returning functions, some formerly big functions can be split into smaller ones, like this changeset. At least GCC is smart enough to inline the split functions back into one. No performance penalty is observed.
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/2486
Diffstat (limited to 'vm_method.c')
-rw-r--r--vm_method.c294
1 files changed, 202 insertions, 92 deletions
diff --git a/vm_method.c b/vm_method.c
index 4abefd5e5f..730ec35cce 100644
--- a/vm_method.c
+++ b/vm_method.c
@@ -211,98 +211,6 @@ static VALUE
}
}
-MJIT_FUNC_EXPORTED void
-rb_method_definition_set(const rb_method_entry_t *me, rb_method_definition_t *def, void *opts)
-{
- *(rb_method_definition_t **)&me->def = def;
-
- if (opts != NULL) {
- switch (def->type) {
- case VM_METHOD_TYPE_ISEQ:
- {
- rb_method_iseq_t *iseq_body = (rb_method_iseq_t *)opts;
- rb_cref_t *method_cref, *cref = iseq_body->cref;
-
- /* setup iseq first (before invoking GC) */
- RB_OBJ_WRITE(me, &def->body.iseq.iseqptr, iseq_body->iseqptr);
-
- if (0) vm_cref_dump("rb_method_definition_create", cref);
-
- if (cref) {
- method_cref = cref;
- }
- else {
- method_cref = vm_cref_new_toplevel(GET_EC()); /* TODO: can we reuse? */
- }
-
- RB_OBJ_WRITE(me, &def->body.iseq.cref, method_cref);
- return;
- }
- case VM_METHOD_TYPE_CFUNC:
- {
- const rb_method_cfunc_t *p = (const rb_method_cfunc_t *)opts;
- rb_method_cfunc_t c = {
- p->func,
- call_cfunc_invoker_func(p->argc),
- p->argc,
- };
- memcpy((void *)&def->body.cfunc, &c, sizeof c);
- return;
- }
- case VM_METHOD_TYPE_ATTRSET:
- case VM_METHOD_TYPE_IVAR:
- {
- const rb_execution_context_t *ec = GET_EC();
- rb_control_frame_t *cfp;
- int line;
-
- memcpy((void *)&def->body.attr, &(rb_method_attr_t) { (ID)(VALUE)opts }, sizeof(rb_method_attr_t));
-
- cfp = rb_vm_get_ruby_level_next_cfp(ec, ec->cfp);
-
- if (cfp && (line = rb_vm_get_sourceline(cfp))) {
- VALUE location = rb_ary_new3(2, rb_iseq_path(cfp->iseq), INT2FIX(line));
- RB_OBJ_WRITE(me, &def->body.attr.location, rb_ary_freeze(location));
- }
- else {
- VM_ASSERT(def->body.attr.location == 0);
- }
- return;
- }
- case VM_METHOD_TYPE_BMETHOD:
- memcpy((void *)&def->body.bmethod, &(rb_method_bmethod_t) { (VALUE)opts }, sizeof(rb_method_bmethod_t));
- RB_OBJ_WRITTEN(me, &def->body.bmethod.proc, (VALUE)opts);
- return;
- case VM_METHOD_TYPE_NOTIMPLEMENTED:
- {
- rb_method_cfunc_t f = { rb_f_notimplement, call_cfunc_m1, -1, };
- memcpy((void *)&def->body.cfunc, &f, sizeof f);
- return;
- }
- case VM_METHOD_TYPE_OPTIMIZED:
- {
- enum method_optimized_type t = (enum method_optimized_type)opts;
- memcpy((void *)&def->body.optimize_type, &t, sizeof t);
- return;
- }
- case VM_METHOD_TYPE_REFINED:
- {
- const rb_method_refined_t *refined = (rb_method_refined_t *)opts;
- RB_OBJ_WRITE(me, &def->body.refined.orig_me, refined->orig_me);
- RB_OBJ_WRITE(me, &def->body.refined.owner, refined->owner);
- return;
- }
- case VM_METHOD_TYPE_ALIAS:
- RB_OBJ_WRITE(me, &def->body.alias.original_me, (rb_method_entry_t *)opts);
- return;
- case VM_METHOD_TYPE_ZSUPER:
- case VM_METHOD_TYPE_UNDEF:
- case VM_METHOD_TYPE_MISSING:
- return;
- }
- }
-}
-
static void
method_definition_reset(const rb_method_entry_t *me)
{
@@ -339,6 +247,208 @@ method_definition_reset(const rb_method_entry_t *me)
}
}
+static rb_cref_t*
+the_top_cref(void)
+{
+ static rb_cref_t *top = NULL;
+ if (!top) {
+ top = vm_cref_new_toplevel(GET_EC());
+ rb_gc_register_mark_object((VALUE)top); // cref is an IMEMO.
+ }
+ return top;
+}
+
+static rb_method_iseq_t
+the_method_iseq(const rb_method_iseq_t *p)
+{
+ return (rb_method_iseq_t) {
+ .iseqptr = p->iseqptr,
+ .cref = p->cref ? p->cref : the_top_cref(),
+ };
+}
+
+static rb_method_cfunc_t
+the_method_cfunc(const rb_method_cfunc_t *p)
+{
+ return (rb_method_cfunc_t) {
+ .func = p->func,
+ .invoker = call_cfunc_invoker_func(p->argc),
+ .argc = p->argc,
+ };
+}
+
+static VALUE
+the_location(void)
+{
+ const rb_execution_context_t *ec = GET_EC();
+ const rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(ec, ec->cfp);
+ int line;
+
+ if (!cfp) {
+ return Qnil;
+ }
+ else if (! (line = rb_vm_get_sourceline(cfp))) {
+ return Qnil;
+ }
+ else {
+ VALUE loc = rb_ary_new3(2, rb_iseq_path(cfp->iseq), INT2FIX(line));
+ rb_ary_freeze(loc);
+ return loc;
+ }
+}
+
+static rb_method_attr_t
+the_method_attr(const void *p)
+{
+ return (rb_method_attr_t) {
+ .id = (ID)(VALUE)p,
+ .location = the_location(),
+ };
+}
+
+static rb_method_bmethod_t
+the_method_bmethod(const void *p)
+{
+ return (rb_method_bmethod_t) {
+ .proc = (VALUE)p,
+ .hooks = NULL,
+ };
+}
+
+static rb_method_cfunc_t
+the_method_notimplemented(void)
+{
+ return (rb_method_cfunc_t) {
+ .func = rb_f_notimplement,
+ .invoker = call_cfunc_m1,
+ .argc = -1,
+ };
+}
+
+static enum method_optimized_type
+the_method_optimized(const void *p)
+{
+ return (enum method_optimized_type)p;
+}
+
+static rb_method_refined_t
+the_method_refined(const rb_method_refined_t *p)
+{
+ return (rb_method_refined_t) {
+ .orig_me = p->orig_me,
+ .owner = p->owner,
+ };
+}
+
+static rb_method_alias_t
+the_method_alias(const rb_method_entry_t *p)
+{
+ return (rb_method_alias_t) {
+ .original_me = p,
+ };
+}
+
+static rb_method_definition_t
+rb_method_definition_new(rb_method_type_t type, ID mid, const void *opts)
+{
+ switch (type) {
+ case VM_METHOD_TYPE_ISEQ:
+ return (rb_method_definition_t) {
+ .type = type,
+ .original_id = mid,
+ .body = {
+ .iseq = the_method_iseq(opts),
+ }
+ };
+
+ case VM_METHOD_TYPE_CFUNC:
+ return (rb_method_definition_t) {
+ .type = type,
+ .original_id = mid,
+ .body = {
+ .cfunc = the_method_cfunc(opts),
+ }
+ };
+
+ case VM_METHOD_TYPE_ATTRSET:
+ case VM_METHOD_TYPE_IVAR:
+ return (rb_method_definition_t) {
+ .type = type,
+ .original_id = mid,
+ .body = {
+ .attr = the_method_attr(opts),
+ }
+ };
+
+ case VM_METHOD_TYPE_BMETHOD:
+ return (rb_method_definition_t) {
+ .type = type,
+ .original_id = mid,
+ .body = {
+ .bmethod = the_method_bmethod(opts),
+ }
+ };
+
+ case VM_METHOD_TYPE_NOTIMPLEMENTED:
+ return (rb_method_definition_t) {
+ .type = type,
+ .original_id = mid,
+ .body = {
+ .cfunc = the_method_notimplemented(),
+ }
+ };
+
+ case VM_METHOD_TYPE_OPTIMIZED:
+ return (rb_method_definition_t) {
+ .type = type,
+ .original_id = mid,
+ .body = {
+ .optimize_type = the_method_optimized(opts),
+ }
+ };
+
+ case VM_METHOD_TYPE_REFINED:
+ return (rb_method_definition_t) {
+ .type = type,
+ .original_id = mid,
+ .body = {
+ .refined = the_method_refined(opts),
+ }
+ };
+
+ case VM_METHOD_TYPE_ALIAS:
+ return (rb_method_definition_t) {
+ .type = type,
+ .original_id = mid,
+ .body = {
+ .alias = the_method_alias(opts),
+ }
+ };
+
+ case VM_METHOD_TYPE_ZSUPER:
+ case VM_METHOD_TYPE_UNDEF:
+ case VM_METHOD_TYPE_MISSING:
+ return (rb_method_definition_t) {
+ .type = type,
+ .original_id = mid,
+ };
+ }
+
+ UNREACHABLE_RETURN((rb_method_definition_t){0});
+}
+
+MJIT_FUNC_EXPORTED void
+rb_method_definition_set(const rb_method_entry_t *me, rb_method_definition_t *def, void *opts)
+{
+ if (opts) {
+ rb_method_definition_t template =
+ rb_method_definition_new(def->type, def->original_id, opts);
+ memcpy(def, &template, sizeof template);
+ }
+ memcpy((void *)&me->def, &def, sizeof def);
+ method_definition_reset(me);
+}
+
MJIT_FUNC_EXPORTED const rb_method_definition_t *
rb_method_definition_create(rb_method_type_t type, ID mid)
{