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

Improve MatchData#dup #1792

Merged
merged 4 commits into from
Nov 5, 2019
Merged

Improve MatchData#dup #1792

merged 4 commits into from
Nov 5, 2019

Conversation

chrisseaton
Copy link
Collaborator

Authored by @XrXr.

Shopify#1

@eregon
Copy link
Member

eregon commented Nov 4, 2019

Is there anything that relies on MatchData.allocate "working"?
If not, it could be tempting to just not allow MatchData.allocate and raise (as it was).


public class MatchDataGuards {
public static boolean isInitialized(DynamicObject matchData) {
return Layouts.MATCH_DATA.getRegexp(matchData) != null;
Copy link
Member

Choose a reason for hiding this comment

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

Could you check getSource(matchData) != null here?
getRegexp() can already return multiple kinds of values (see comment).

@TruffleBoundary
@Specialization
protected DynamicObject allocate(DynamicObject rubyClass) {
throw new RaiseException(getContext(), coreExceptions().typeErrorAllocatorUndefinedFor(rubyClass, this));
protected DynamicObject allocate(DynamicObject rubyClass, @Cached AllocateObjectNode allocateNode) {
Copy link
Member

Choose a reason for hiding this comment

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

@Cached should be on its own line (jt checkstyle checks that)

@eregon eregon self-assigned this Nov 4, 2019
@XrXr
Copy link
Contributor

XrXr commented Nov 4, 2019

Is there anything that relies on MatchData.allocate "working"?

The goal for this was to get MatchData#dup to work. MRI just uses Kernel#dup for that, which requires allocate to work. This PR also makes MatchData#clone work, which also requires allocate. Alternatively, we could implement each specifically for MatchData but I think we will end up with the same amount of complexity.

Don't really have a strong opinion on this either way, just following MRI here. One thing to note is that there is no specs to make sure dup and clone work correctly w.r.t. copying instance variable and freeze state and things like that. It would probably be a good idea to have those tests going whichever implementation we end up going with.

@eregon
Copy link
Member

eregon commented Nov 5, 2019

The goal for this was to get MatchData#dup to work. MRI just uses Kernel#dup for that, which requires allocate to work. This PR also makes MatchData#clone work, which also requires allocate.

Indeed, that's how MRI does it, and it's generally good to follow MRI behavior for maximum compatibility.
Do you know what uses MatchData#dup? I can't think of any use case, since the internal MatchData fields are basically all immutable.

Alternatively, we could implement each specifically for MatchData but I think we will end up with the same amount of complexity.

I think it would make the changes more localized, by just having to implement MatchData#dup and MatchData#clone.

  • We could also come up with our own protocol for duping with Kernel#dup without needing to mutate the object's internal fields (e.g., klass.allocate_copy(original)), but that seems quite a bit of complication just for this case (there might be other classes benefiting from such an approach though). The main disadvantage there would be it's probably hard to make it fully compatible.
  • I think MatchData should actually be frozen, and then dup/clone would just return self. But that's not how it is in MRI currently, and that would likely be less compatible with user code.

Don't really have a strong opinion on this either way, just following MRI here. One thing to note is that there is no specs to make sure dup and clone work correctly w.r.t. copying instance variable and freeze state and things like that. It would probably be a good idea to have those tests going whichever implementation we end up going with.

I think those specs are less necessary with your approach, there we can rely on Kernel#{dup,clone} specs.

I'll merge this approach, it's straightforward and aims for maximum compatibility with MRI.
Thank you for the fix and the specs!

@eregon eregon added this to the 20.0.0 milestone Nov 5, 2019
@eregon eregon added the in-ci The PR is being tested in CI. Do not push new commits. label Nov 5, 2019
@eregon
Copy link
Member

eregon commented Nov 5, 2019

MRI issue to discuss whether we can make MatchData frozen:
https://bugs.ruby-lang.org/issues/16294
I'm tempted by that approach, it sounds a lot cleaner.

graalvmbot pushed a commit that referenced this pull request Nov 5, 2019
PullRequest: truffleruby/1116
@graalvmbot graalvmbot merged commit 86a00a0 into oracle:master Nov 5, 2019
@eregon
Copy link
Member

eregon commented Nov 30, 2019

Nobu made MatchData#allocate undefined, so I think I'll go for a similar approach in TruffleRuby:
https://bugs.ruby-lang.org/projects/ruby-trunk/repository/git/revisions/aa94245a09887f95bc0cd353b3462108d76d13ed/diff

@eregon
Copy link
Member

eregon commented Nov 30, 2019

What we can do here is leave __allocate__ defined as it is to allow the normal copy mechanism, but remove the user-visible allocate to make it clear we don't support half-initialized MatchData.

@eregon
Copy link
Member

eregon commented Dec 2, 2019

I did that in 32791da.

@chrisseaton chrisseaton deleted the match-data-dup branch December 2, 2019 18:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in-ci The PR is being tested in CI. Do not push new commits. oca-signed shopify
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants