Skip to content
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

Reduce usage of object_id in core gems #9276

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

amomchilov
Copy link
Contributor

@amomchilov amomchilov commented Dec 18, 2023

Related: ruby/psych#663

Since Ruby 2.7, object_id became more expensive, particularly on its first call for a particular object. @jemmaissroff has a great blog post about it.

This PR aims to minimize its use by:

  1. Replacing Hashes keyed with .objetc_id values with Hash#compare_by_identity
  2. Replacing object_id comparisons with equal?

In both cases, we can trigger fewer accidental object ID assignments.

Update: All of the "meat" of this PR was moved out to the upstream gems' repos. What's left is just a few small changes like adding docs and fixing a typo etc.

@amomchilov amomchilov force-pushed the reduce-object_id-use branch 3 times, most recently from 3d686f7 to 9a11a34 Compare December 18, 2023 09:25
@@ -1232,10 +1232,7 @@ ensure_class_or_module(VALUE obj)
static VALUE
hidden_identity_hash_new(void)
{
VALUE hash = rb_ident_hash_new();

RBASIC_CLEAR_CLASS(hash); /* hide from ObjectSpace */
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Looking through uses of rb_ident_hash_new, I ran into this. Most cases use rb_obj_hide, but this uses RBASIC_CLEAR_CLASS. Is the difference intentional?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@nobu Do you have any context on this?

Copy link
Member

Choose a reason for hiding this comment

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

This line predates commit:adf1c94ffe75, where rb_obj_hide was added.
Just added to fix https://bugs.ruby-lang.org/issues/8204, but didn't change already existing code all.
Maybe for unnecessary SPECIAL_CONST_P check.
It would be OK to replace this line with rb_obj_hide, I think.

lib/ostruct.rb Outdated Show resolved Hide resolved
Comment on lines 16 to 18
def ==(other)
object_id == other.object_id
equal?(other)
end
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Alternatively, I could have deleted the Struct#== implementation with:

Suggested change
def ==(other)
object_id == other.object_id
equal?(other)
end
remove_method(:==)

This would cause the Object#== implementation to be inherited (which is identity-based), but it's much less clear, though.

lib/set.rb Outdated Show resolved Hide resolved
object.c Outdated
@@ -98,6 +98,15 @@ rb_obj_embedded_size(uint32_t numiv)
return offsetof(struct RObject, as.ary) + (sizeof(VALUE) * numiv);
}

/*!
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Unrelated, but this was unclear (what does "hide" mean?) and didn't have any docs, so I just added some.

Copy link
Member

Choose a reason for hiding this comment

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

Hide the object from ObjectSpace, as written in hidden_identity_hash_new comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Heh yeah I got it, but I didn’t in first read, which is why I added the doc comment for future readers

Copy link
Member

@nobu nobu left a comment

Choose a reason for hiding this comment

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

The files under lib have each own upstreams.
Please send PR to the upstreams for such files.

eval.c Outdated Show resolved Hide resolved
@amomchilov
Copy link
Contributor Author

amomchilov commented Dec 18, 2023

@nobu ah interesting…
Is there any way to synchronize the changes to set and ostruct? The two share use of Thread.current[InspectKey], whose usage pattern would need to change (because it’s type would change from an Array to and ident Set).

Would I need to write the patch in each of the two gems in a way that’s backwards-compatible with the other gem being in the older version?

Update: I think I figured it out. I opened:

@nobu
Copy link
Member

nobu commented Dec 19, 2023

It was moved there once, but partially rewritten as an extension library at #2576.
So that repo is outdated.

object.c Outdated Show resolved Hide resolved
@amomchilov
Copy link
Contributor Author

Hey @nobu, I incorporated the changes you mentioned.

Could you please merge what's left of this PR, and review the smaller PRs I opened on the upstream gems?

@amomchilov amomchilov requested a review from nobu January 5, 2024 15:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
2 participants