Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Fix object_id for classes and modules in namespace context #13315

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 14, 2025

Conversation

casperisfine
Copy link
Contributor

Given classes and modules have a different set of fields in every namespace, we can't store the object_id in fields for them.

First because the shape_id is different if an object has an object_id, so we'd lookup the ID in a st_table that may not have it and crash.
But even if somehow each class_ext had a shape_id, the object_id would be different in every namespace, and as far as I understand that's not how namespaces are supposed to work.

Given that some space was freed in RClass we can store it there instead, which has the benefit of allowing it to be lockless (not fully in this PR but I have another one to generate object IDs atomically).

@tagomoris did I get namespaces correctly?

Also cc @jhawthorn

This comment has been minimized.

@casperisfine casperisfine force-pushed the fix-obj-id-namespace branch 3 times, most recently from d0e8149 to 062ea1c Compare May 13, 2025 10:07
@tagomoris
Copy link
Contributor

@byroot When the rb_classext_t is copied at the first time (for the klass), it evict shapes: https://github.com/ruby/ruby/blob/master/internal/class.h#L406

As far as I understood, the root cause of this problem in the current implementation is object_id is not stored in the ivar tbl (not shape because evicted) in a namespace B after:

  1. MyClass.object_id is not set yet
  2. MyClass's rb_classext_t is copied from namespace A to B
  3. MyClass.object_id is set (stored into ivar table) and the flag about object_id is set in the namespace A
  4. MyClass.object_id is referred in namespace B, the flag says the object_id is stored, but not exists in the ivar tbl

My original idea (popped up in talking w/ @ko1 ) to solve this problem is, when the object_id is set to ivar tbl, set the value into all ivar tables in each rb_classext_t. Once object_id value is set into the ivar tbl of the root namespace, it'll be copied to other namespaces.

@byroot
Copy link
Member

byroot commented May 13, 2025

My original idea

That's another possibility indeed. Just seem more work than this PR, and this PR has the advantage of getting rid of a known Ractor contention point at the same time.

@tagomoris
Copy link
Contributor

From my viewpoint:

@byroot
Copy link
Member

byroot commented May 13, 2025

RClass (&classext) size: +1 VALUE

Well, technically these bytes are currently wasted, so the size in unchanged. And you solution would mean one more st_table_entry per namepace, so +3 VALUE for each class that has an object_id.

@tagomoris
Copy link
Contributor

This patch looks really nice to me.
The only concern is the size of RClass + classext. We'll be able to reduce 5 * VALUE_SIZE eventually and in that case +1 VALUE should be ok, I think.

@tagomoris
Copy link
Contributor

Ah, probably I misunderstand something.
@byroot I'm ok if adding the field in RClass is not a problem.

@byroot
Copy link
Member

byroot commented May 13, 2025

Ah, probably I misunderstand something.

No, you were right, I'm the one that was wrong, this indeed make classes one VALUE larger.

@tagomoris
Copy link
Contributor

@byroot The simplicity is important, I think. So Let's merge this change, and let's rethink later when we need to reduce a VALUE from RClass in the future. WDYT?

@casperisfine
Copy link
Contributor Author

WDYT?

Yes, I'd rather get a fix out, because right now object_id crashes when namespaces are enabled, which prevent testing them any further. I'll wait for @jhawthorn's opinion though.

@casperisfine casperisfine force-pushed the fix-obj-id-namespace branch 2 times, most recently from 1e64121 to 054dba1 Compare May 13, 2025 15:40
Copy link
Member

@jhawthorn jhawthorn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me. One place I think TSan will complain, but I'm not sure it's worth caring about.

gc.c Outdated
static VALUE
class_object_id(VALUE klass)
{
VALUE id = RCLASS(klass)->object_id;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be nice to do an atomic load here, otherwise TSan will complain, but I think in practice it doesn't matter here (ie. an atomic load with memory order relaxed should work). So not a blocker.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, I had to implement RUBY_ATOMIC_VALUE_LOAD.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I couldn't make it work, so I used the same hack you used in string.c. Sorry.

@casperisfine casperisfine changed the title Fix object_id for classes in modules in namespace context Fix object_id for classes and modules in namespace context May 13, 2025
@casperisfine casperisfine force-pushed the fix-obj-id-namespace branch 2 times, most recently from 74fc4ed to ee3bcd0 Compare May 13, 2025 21:25
@tagomoris
Copy link
Contributor

How about adding RCLASS_OBJECT_ID macro to control the access to RCLASS(klass)->object_id?

@casperisfine casperisfine force-pushed the fix-obj-id-namespace branch from ee3bcd0 to 710a18c Compare May 14, 2025 07:38
@casperisfine
Copy link
Contributor Author

How about adding RCLASS_OBJECT_ID macro to control the access to RCLASS(klass)->object_id?

I don't think it adds a lot of value because the object_id isn't going to be namespaced.

Given classes and modules have a different set of fields in every
namespace, we can't store the object_id in fields for them.

Given that some space was freed in `RClass` we can store it there
instead.
@casperisfine casperisfine force-pushed the fix-obj-id-namespace branch from b7022f2 to e53c2ea Compare May 14, 2025 07:56
@byroot byroot merged commit 9400119 into ruby:master May 14, 2025
79 checks passed
@casperisfine casperisfine deleted the fix-obj-id-namespace branch May 14, 2025 14:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants