Feature #21966
closedRemove rb_obj_class runtime check on rb_define_alloc_func returned objects
Description
I want to remove the following runtime check in class_call_alloc_func, replacing it with a RUBY_ASSERT (so we would still have the check, but only on a debug build).
if (rb_obj_class(obj) != rb_class_real(klass)) {
rb_raise(rb_eTypeError, "wrong instance allocation");
}
This checks that the value returned from the function registered with rb_define_alloc_func is of the correct class. When this was first introduced in 1fe40b7cc5 (by Matz on 2001-10-03), allocation was done via user-defined Object#allocate, so it made sense to have a runtime check in release builds. Now that it's defined via rb_define_alloc_func in the C extension API, I don't think it's necessary.
The check is surprisingly expensive. Removing it makes Object.new about 10% faster. It allows the C compiler to optimize the call to the function pointer as a tail-call. Removing this also allows ZJIT/YJIT to call the function directly (ZJIT already does this by having a list of known safe allocation functions). The diff in the assembly from skipping this is substantial https://gist.github.com/jhawthorn/20834b654bec4ba0bafee729592d5156 (though much of that is rb_class_real which I also have plans to improve).
There's no way for users to ever have seen this check, other than by writing a misbehaving C extension, which returns objects with the wrong class.
https://github.com/ruby/ruby/pull/16571
I don't think this should be controversial, but I'm filing a feature to make sure it has visibility. If anyone has concerns I'll revert the change and discuss here.
Updated by jhawthorn (John Hawthorn) 1 day ago
- Status changed from Open to Closed
Applied in changeset git|851b8f852313c361465cf760701e23db0ea4d474.
Remove class alloc check
This checks that the value returned from the function registered with
rb_define_alloc_func is of the correct class. When this was first
introduced in 1fe40b7cc5 (by Matz on 2001-10-03), allocation was done
via user-defined Object#allocate, so it made sense to have a runtime
check in release builds. Now that it's defined via rb_define_alloc_func
in the C extension API, I don't think it's necessary.
The check is surprisingly expensive. Removing it makes Object.new about
10% faster. It allows the C compiler to optimize the call to the
function pointer as a tail-call. Removing this also allows ZJIT/YJIT to
call the function directly (ZJIT already does this by having a list of
known safe allocation functions).
There's no way for users to ever have seen this check, other than by
writing a misbehaving C extension, which returns objects with the wrong
class.
[Feature #21966]