Project

General

Profile

Actions

Feature #21863

open

Add RBASIC_FLAGS() and RBASIC_SET_FLAGS()

Feature #21863: Add RBASIC_FLAGS() and RBASIC_SET_FLAGS()

Added by Eregon (Benoit Daloze) 18 days ago. Updated 11 days ago.

Status:
Open
Assignee:
-
Target version:
-
[ruby-core:124684]

Description

Currently there is RBASIC_CLASS() which is the same as RBASIC(obj)->klass on CRuby but also checks it's called on a valid object:
https://github.com/ruby/ruby/blob/86dba8cfaeabb3b86df921da24b3243b9ce4ab2a/include/ruby/internal/core/rbasic.h#L159-L170

I would like to add RBASIC_FLAGS() and RBASIC_SET_FLAGS(), which could be defined like this on CRuby:

#define RBASIC_FLAGS(obj) (RBASIC(obj)->flags)
#define RBASIC_SET_FLAGS(obj, flags_to_set) (RBASIC(obj)->flags = flags_to_set)

This would let native extensions access those flags without relying on the specific fields, layout and existence of a RBasic struct.

My main motivation here is that TruffleRuby, the alternative Ruby implementation with the most complete native extension support, cannot support having mutable fields in RBasic.
The reason is because flags are mutable, it would be impossible to find out when the user writes to the flags if they write with just RBASIC(obj)->flags = v.
And since the state related to flags is held internally on the Java object, writing to native memory would do nothing, which would be incompatible.
With these macros we can know when the user writes to the flags and update the internal representation.
In fact, TruffleRuby already implements these macros, since this comment.
I would like to make it a standard C API to increase adoption and make it easier to discover.

This would also be useful on CRuby to do additional checks when reading and writing flags:

  • We could add RBIMPL_ASSERT_OR_ASSUME(!RB_SPECIAL_CONST_P(obj)); like RBASIC_CLASS does.
  • We could check that the frozen flag is not removed.
  • We could check that the frozen flag is consistent with the frozen flag on the object shape (if CRuby has a frozen flag in the shape).
  • We could check that the shape is not changed by native extensions this way (since the shape is stored in flags on 64-bit machines).
  • CRuby would be able to evolve the representation of RBasic more freely in the future.

I'll note that there are already some macros/functions to manipulate flags such as RB_FL_TEST(), however they don't allow just reading or writing the flags:
https://github.com/ruby/ruby/blob/86dba8cfaeabb3b86df921da24b3243b9ce4ab2a/include/ruby/internal/fl_type.h#L95-L107
However it seems clear that C extensions do read and write the RBasic->flags field currently and these RB_FL_*() macros/functions are not enough, so RBASIC_FLAGS() and RBASIC_SET_FLAGS() would be obvious replacements.
Here is a gem-codesearch for /RBASIC\(.+\)->flags/: https://gist.github.com/eregon/5866bd86e626ae723b5b16d935af8f94

An alternative would be to deprecate the RBasic->flags field entirely and eventually hide it, and don't provide a replacement for direct reading/writing flags, but that would break a bunch of native extensions, so it does not seem actionable.
With this proposal we won't break anything and we'll actually get finer control over accesses to flags if e.g. we want to prevent some invariant-breaking changes.

Actions

Also available in: PDF Atom