summaryrefslogtreecommitdiff
path: root/vm_method.c
diff options
context:
space:
mode:
Diffstat (limited to 'vm_method.c')
-rw-r--r--vm_method.c34
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;
}