diff options
Diffstat (limited to 'vm_method.c')
-rw-r--r-- | vm_method.c | 34 |
1 files changed, 31 insertions, 3 deletions
diff --git a/vm_method.c b/vm_method.c index 73a431ce93..fb217ef43d 100644 --- a/vm_method.c +++ b/vm_method.c @@ -1786,7 +1786,14 @@ cache_callable_method_entry(VALUE klass, ID mid, const rb_callable_method_entry_ #endif } else { - vm_ccs_create(klass, cc_tbl, mid, cme); + if (rb_multi_ractor_p()) { + VALUE new_cc_tbl = rb_vm_cc_table_dup(cc_tbl); + vm_ccs_create(klass, new_cc_tbl, mid, cme); + RB_OBJ_ATOMIC_WRITE(klass, &RCLASSEXT_CC_TBL(RCLASS_EXT_WRITABLE(klass)), new_cc_tbl); + } + else { + vm_ccs_create(klass, cc_tbl, mid, cme); + } } } @@ -1815,6 +1822,25 @@ callable_method_entry_or_negative(VALUE klass, ID mid, VALUE *defined_class_ptr) const rb_callable_method_entry_t *cme; VM_ASSERT_TYPE2(klass, T_CLASS, T_ICLASS); + + /* Fast path: lock-free read from cache */ + VALUE cc_tbl = RUBY_ATOMIC_VALUE_LOAD(RCLASS_WRITABLE_CC_TBL(klass)); + if (cc_tbl) { + VALUE ccs_data; + if (rb_managed_id_table_lookup(cc_tbl, mid, &ccs_data)) { + struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_data; + VM_ASSERT(vm_ccs_p(ccs)); + + if (LIKELY(!METHOD_ENTRY_INVALIDATED(ccs->cme))) { + VM_ASSERT(ccs->cme->called_id == mid); + if (defined_class_ptr != NULL) *defined_class_ptr = ccs->cme->defined_class; + RB_DEBUG_COUNTER_INC(ccs_found); + return ccs->cme; + } + } + } + + /* Slow path: need to lock and potentially populate cache */ RB_VM_LOCKING() { cme = cached_callable_method_entry(klass, mid); @@ -2952,13 +2978,14 @@ rb_mod_ruby2_keywords(int argc, VALUE *argv, VALUE module) switch (me->def->type) { case VM_METHOD_TYPE_ISEQ: if (ISEQ_BODY(me->def->body.iseq.iseqptr)->param.flags.has_rest && + !ISEQ_BODY(me->def->body.iseq.iseqptr)->param.flags.has_post && !ISEQ_BODY(me->def->body.iseq.iseqptr)->param.flags.has_kw && !ISEQ_BODY(me->def->body.iseq.iseqptr)->param.flags.has_kwrest) { ISEQ_BODY(me->def->body.iseq.iseqptr)->param.flags.ruby2_keywords = 1; rb_clear_method_cache(module, name); } else { - rb_warn("Skipping set of ruby2_keywords flag for %"PRIsVALUE" (method accepts keywords or method does not accept argument splat)", QUOTE_ID(name)); + rb_warn("Skipping set of ruby2_keywords flag for %"PRIsVALUE" (method accepts keywords or post arguments or method does not accept argument splat)", QUOTE_ID(name)); } break; case VM_METHOD_TYPE_BMETHOD: { @@ -2971,13 +2998,14 @@ rb_mod_ruby2_keywords(int argc, VALUE *argv, VALUE module) const struct rb_captured_block *captured = VM_BH_TO_ISEQ_BLOCK(procval); const rb_iseq_t *iseq = rb_iseq_check(captured->code.iseq); if (ISEQ_BODY(iseq)->param.flags.has_rest && + !ISEQ_BODY(iseq)->param.flags.has_post && !ISEQ_BODY(iseq)->param.flags.has_kw && !ISEQ_BODY(iseq)->param.flags.has_kwrest) { ISEQ_BODY(iseq)->param.flags.ruby2_keywords = 1; rb_clear_method_cache(module, name); } else { - rb_warn("Skipping set of ruby2_keywords flag for %"PRIsVALUE" (method accepts keywords or method does not accept argument splat)", QUOTE_ID(name)); + rb_warn("Skipping set of ruby2_keywords flag for %"PRIsVALUE" (method accepts keywords or post arguments or method does not accept argument splat)", QUOTE_ID(name)); } break; } |