mirror of
https://github.com/ruby/ruby.git
synced 2026-11-08 01:20:26 +08:00
Defer the optimized method redefinition warning when refining under the VM lock
Since add_refined_method_entry() is called from rb_method_entry_make()
under the VM lock, it has to collect the performance warning in the
caller's method_entry_warnings like the rest of rb_method_entry_make().
Otherwise refining an optimized method that the refined class defines
itself, such as
refine(Integer) { def +(other) end }
with Warning[:performance] enabled and a second Ractor around, warns with
the lock held and trips the critical section assertion in
rb_vm_check_ints.
The struct moves up so that add_refined_method_entry() can see its
members.
This commit is contained in:
parent
358733a634
commit
9022974666
Notes:
git
2026-11-05 15:34:59 +00:00
35
vm_method.c
35
vm_method.c
@ -1384,7 +1384,22 @@ lookup_method_table(VALUE klass, ID id)
|
||||
}
|
||||
}
|
||||
|
||||
struct method_entry_warnings;
|
||||
/* rb_method_entry_make() runs under the VM lock, where it must not warn:
|
||||
* rb_warn() and rb_category_warn() dispatch Warning.warn and write to $stderr,
|
||||
* either of which can check for interrupts. It formats the messages instead,
|
||||
* and the caller emits them once the lock is released.
|
||||
*
|
||||
* The performance warning cannot even be formatted under the lock, because
|
||||
* rb_class2name() names an anonymous class with a "%"PRIsVALUE" that calls
|
||||
* #to_s, so the method entries to warn about are collected as they are found.
|
||||
* There can be more than one: the redefinition check walks the whole subclass
|
||||
* tree. */
|
||||
struct method_entry_warnings {
|
||||
VALUE redefined; /* $VERBOSE only */
|
||||
VALUE problem;
|
||||
VALUE performance; /* method entries, RB_WARN_CATEGORY_PERFORMANCE */
|
||||
};
|
||||
|
||||
static rb_method_entry_t *rb_method_entry_make(VALUE klass, ID mid, VALUE defined_class, rb_method_visibility_t visi,
|
||||
rb_method_type_t type, rb_method_definition_t *def, ID original_id, void *opts,
|
||||
struct method_entry_warnings *warnings);
|
||||
@ -1397,7 +1412,7 @@ add_refined_method_entry(VALUE refined_class, ID mid, struct method_entry_warnin
|
||||
rb_method_entry_t *me = lookup_method_table(refined_class, mid);
|
||||
|
||||
if (me) {
|
||||
make_method_entry_refined(refined_class, me, NULL);
|
||||
make_method_entry_refined(refined_class, me, warnings ? &warnings->performance : NULL);
|
||||
rb_clear_method_cache(refined_class, mid);
|
||||
}
|
||||
else if (warnings) {
|
||||
@ -1477,22 +1492,6 @@ method_entry_modify_check(VALUE klass, rb_method_type_t type)
|
||||
}
|
||||
}
|
||||
|
||||
/* rb_method_entry_make() runs under the VM lock, where it must not warn:
|
||||
* rb_warn() and rb_category_warn() dispatch Warning.warn and write to $stderr,
|
||||
* either of which can check for interrupts. It formats the messages instead,
|
||||
* and the caller emits them once the lock is released.
|
||||
*
|
||||
* The performance warning cannot even be formatted under the lock, because
|
||||
* rb_class2name() names an anonymous class with a "%"PRIsVALUE" that calls
|
||||
* #to_s, so the method entries to warn about are collected as they are found.
|
||||
* There can be more than one: the redefinition check walks the whole subclass
|
||||
* tree. */
|
||||
struct method_entry_warnings {
|
||||
VALUE redefined; /* $VERBOSE only */
|
||||
VALUE problem;
|
||||
VALUE performance; /* method entries, RB_WARN_CATEGORY_PERFORMANCE */
|
||||
};
|
||||
|
||||
static void
|
||||
method_entry_warnings_emit(const struct method_entry_warnings *warnings)
|
||||
{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user